diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/pctl/parental_control_service.cpp | 441 | ||||
| -rw-r--r-- | src/core/hle/service/pctl/parental_control_service.h | 74 | ||||
| -rw-r--r-- | src/core/hle/service/pctl/pctl_module.cpp | 468 |
4 files changed, 518 insertions, 467 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9e913fb10..d0fdae8db 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -893,6 +893,8 @@ add_library(core STATIC | |||
| 893 | hle/service/os/mutex.h | 893 | hle/service/os/mutex.h |
| 894 | hle/service/pcie/pcie.cpp | 894 | hle/service/pcie/pcie.cpp |
| 895 | hle/service/pcie/pcie.h | 895 | hle/service/pcie/pcie.h |
| 896 | hle/service/pctl/parental_control_service.cpp | ||
| 897 | hle/service/pctl/parental_control_service.h | ||
| 896 | hle/service/pctl/pctl.cpp | 898 | hle/service/pctl/pctl.cpp |
| 897 | hle/service/pctl/pctl.h | 899 | hle/service/pctl/pctl.h |
| 898 | hle/service/pctl/pctl_module.cpp | 900 | hle/service/pctl/pctl_module.cpp |
diff --git a/src/core/hle/service/pctl/parental_control_service.cpp b/src/core/hle/service/pctl/parental_control_service.cpp new file mode 100644 index 000000000..4248b0184 --- /dev/null +++ b/src/core/hle/service/pctl/parental_control_service.cpp | |||
| @@ -0,0 +1,441 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/file_sys/control_metadata.h" | ||
| 6 | #include "core/file_sys/patch_manager.h" | ||
| 7 | #include "core/hle/service/ipc_helpers.h" | ||
| 8 | #include "core/hle/service/pctl/parental_control_service.h" | ||
| 9 | #include "core/hle/service/pctl/pctl_results.h" | ||
| 10 | |||
| 11 | namespace Service::PCTL { | ||
| 12 | |||
| 13 | IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_) | ||
| 14 | : ServiceFramework{system_, "IParentalControlService"}, capability{capability_}, | ||
| 15 | service_context{system_, "IParentalControlService"} { | ||
| 16 | // clang-format off | ||
| 17 | static const FunctionInfo functions[] = { | ||
| 18 | {1, &IParentalControlService::Initialize, "Initialize"}, | ||
| 19 | {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, | ||
| 20 | {1002, nullptr, "ConfirmLaunchApplicationPermission"}, | ||
| 21 | {1003, nullptr, "ConfirmResumeApplicationPermission"}, | ||
| 22 | {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"}, | ||
| 23 | {1005, nullptr, "ConfirmSystemSettingsPermission"}, | ||
| 24 | {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"}, | ||
| 25 | {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, | ||
| 26 | {1008, nullptr, "EnterRestrictedSystemSettings"}, | ||
| 27 | {1009, nullptr, "LeaveRestrictedSystemSettings"}, | ||
| 28 | {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, | ||
| 29 | {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, | ||
| 30 | {1012, nullptr, "GetRestrictedFeatures"}, | ||
| 31 | {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"}, | ||
| 32 | {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, | ||
| 33 | {1015, nullptr, "ConfirmPlayableApplicationVideo"}, | ||
| 34 | {1016, nullptr, "ConfirmShowNewsPermission"}, | ||
| 35 | {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"}, | ||
| 36 | {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"}, | ||
| 37 | {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"}, | ||
| 38 | {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"}, | ||
| 39 | {1033, nullptr, "SetSafetyLevel"}, | ||
| 40 | {1034, nullptr, "GetSafetyLevelSettings"}, | ||
| 41 | {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"}, | ||
| 42 | {1036, nullptr, "SetCustomSafetyLevelSettings"}, | ||
| 43 | {1037, nullptr, "GetDefaultRatingOrganization"}, | ||
| 44 | {1038, nullptr, "SetDefaultRatingOrganization"}, | ||
| 45 | {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"}, | ||
| 46 | {1042, nullptr, "AddToFreeCommunicationApplicationList"}, | ||
| 47 | {1043, nullptr, "DeleteSettings"}, | ||
| 48 | {1044, nullptr, "GetFreeCommunicationApplicationList"}, | ||
| 49 | {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, | ||
| 50 | {1046, nullptr, "DisableFeaturesForReset"}, | ||
| 51 | {1047, nullptr, "NotifyApplicationDownloadStarted"}, | ||
| 52 | {1048, nullptr, "NotifyNetworkProfileCreated"}, | ||
| 53 | {1049, nullptr, "ResetFreeCommunicationApplicationList"}, | ||
| 54 | {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, | ||
| 55 | {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, | ||
| 56 | {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, | ||
| 57 | {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"}, | ||
| 58 | {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"}, | ||
| 59 | {1201, nullptr, "UnlockRestrictionTemporarily"}, | ||
| 60 | {1202, nullptr, "UnlockSystemSettingsRestriction"}, | ||
| 61 | {1203, nullptr, "SetPinCode"}, | ||
| 62 | {1204, nullptr, "GenerateInquiryCode"}, | ||
| 63 | {1205, nullptr, "CheckMasterKey"}, | ||
| 64 | {1206, nullptr, "GetPinCodeLength"}, | ||
| 65 | {1207, nullptr, "GetPinCodeChangedEvent"}, | ||
| 66 | {1208, nullptr, "GetPinCode"}, | ||
| 67 | {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"}, | ||
| 68 | {1406, nullptr, "GetSettingsLastUpdated"}, | ||
| 69 | {1411, nullptr, "GetPairingAccountInfo"}, | ||
| 70 | {1421, nullptr, "GetAccountNickname"}, | ||
| 71 | {1424, nullptr, "GetAccountState"}, | ||
| 72 | {1425, nullptr, "RequestPostEvents"}, | ||
| 73 | {1426, nullptr, "GetPostEventInterval"}, | ||
| 74 | {1427, nullptr, "SetPostEventInterval"}, | ||
| 75 | {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"}, | ||
| 76 | {1451, nullptr, "StartPlayTimer"}, | ||
| 77 | {1452, nullptr, "StopPlayTimer"}, | ||
| 78 | {1453, nullptr, "IsPlayTimerEnabled"}, | ||
| 79 | {1454, nullptr, "GetPlayTimerRemainingTime"}, | ||
| 80 | {1455, nullptr, "IsRestrictedByPlayTimer"}, | ||
| 81 | {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"}, | ||
| 82 | {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"}, | ||
| 83 | {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"}, | ||
| 84 | {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"}, | ||
| 85 | {1472, nullptr, "CancelNetworkRequest"}, | ||
| 86 | {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"}, | ||
| 87 | {1474, nullptr, "ClearUnlinkedEvent"}, | ||
| 88 | {1601, nullptr, "DisableAllFeatures"}, | ||
| 89 | {1602, nullptr, "PostEnableAllFeatures"}, | ||
| 90 | {1603, nullptr, "IsAllFeaturesDisabled"}, | ||
| 91 | {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"}, | ||
| 92 | {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"}, | ||
| 93 | {1903, nullptr, "GetExemptApplicationListCountForDebug"}, | ||
| 94 | {1904, nullptr, "GetExemptApplicationListForDebug"}, | ||
| 95 | {1905, nullptr, "UpdateExemptApplicationListForDebug"}, | ||
| 96 | {1906, nullptr, "AddToExemptApplicationListForDebug"}, | ||
| 97 | {1907, nullptr, "DeleteFromExemptApplicationListForDebug"}, | ||
| 98 | {1908, nullptr, "ClearExemptApplicationListForDebug"}, | ||
| 99 | {1941, nullptr, "DeletePairing"}, | ||
| 100 | {1951, nullptr, "SetPlayTimerSettingsForDebug"}, | ||
| 101 | {1952, nullptr, "GetPlayTimerSpentTimeForTest"}, | ||
| 102 | {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"}, | ||
| 103 | {2001, nullptr, "RequestPairingAsync"}, | ||
| 104 | {2002, nullptr, "FinishRequestPairing"}, | ||
| 105 | {2003, nullptr, "AuthorizePairingAsync"}, | ||
| 106 | {2004, nullptr, "FinishAuthorizePairing"}, | ||
| 107 | {2005, nullptr, "RetrievePairingInfoAsync"}, | ||
| 108 | {2006, nullptr, "FinishRetrievePairingInfo"}, | ||
| 109 | {2007, nullptr, "UnlinkPairingAsync"}, | ||
| 110 | {2008, nullptr, "FinishUnlinkPairing"}, | ||
| 111 | {2009, nullptr, "GetAccountMiiImageAsync"}, | ||
| 112 | {2010, nullptr, "FinishGetAccountMiiImage"}, | ||
| 113 | {2011, nullptr, "GetAccountMiiImageContentTypeAsync"}, | ||
| 114 | {2012, nullptr, "FinishGetAccountMiiImageContentType"}, | ||
| 115 | {2013, nullptr, "SynchronizeParentalControlSettingsAsync"}, | ||
| 116 | {2014, nullptr, "FinishSynchronizeParentalControlSettings"}, | ||
| 117 | {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, | ||
| 118 | {2016, nullptr, "RequestUpdateExemptionListAsync"}, | ||
| 119 | }; | ||
| 120 | // clang-format on | ||
| 121 | RegisterHandlers(functions); | ||
| 122 | |||
| 123 | synchronization_event = | ||
| 124 | service_context.CreateEvent("IParentalControlService::SynchronizationEvent"); | ||
| 125 | unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent"); | ||
| 126 | request_suspension_event = | ||
| 127 | service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent"); | ||
| 128 | } | ||
| 129 | |||
| 130 | IParentalControlService::~IParentalControlService() { | ||
| 131 | service_context.CloseEvent(synchronization_event); | ||
| 132 | service_context.CloseEvent(unlinked_event); | ||
| 133 | service_context.CloseEvent(request_suspension_event); | ||
| 134 | } | ||
| 135 | |||
| 136 | bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const { | ||
| 137 | if (states.temporary_unlocked) { | ||
| 138 | return true; | ||
| 139 | } | ||
| 140 | if ((states.application_info.parental_control_flag & 1) == 0) { | ||
| 141 | return true; | ||
| 142 | } | ||
| 143 | if (pin_code[0] == '\0') { | ||
| 144 | return true; | ||
| 145 | } | ||
| 146 | if (!settings.is_free_communication_default_on) { | ||
| 147 | return true; | ||
| 148 | } | ||
| 149 | // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here | ||
| 150 | // but as we don't have multiproceses support yet, we can just assume our application is | ||
| 151 | // valid for the time being | ||
| 152 | return true; | ||
| 153 | } | ||
| 154 | |||
| 155 | bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const { | ||
| 156 | if (states.temporary_unlocked) { | ||
| 157 | return true; | ||
| 158 | } | ||
| 159 | if (pin_code[0] == '\0') { | ||
| 160 | return true; | ||
| 161 | } | ||
| 162 | if (!settings.is_stero_vision_restricted) { | ||
| 163 | return false; | ||
| 164 | } | ||
| 165 | return true; | ||
| 166 | } | ||
| 167 | |||
| 168 | void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) { | ||
| 169 | if (settings.disabled) { | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (pin_code[0] == '\0') { | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | settings.is_stero_vision_restricted = is_restricted; | ||
| 177 | } | ||
| 178 | |||
| 179 | void IParentalControlService::Initialize(HLERequestContext& ctx) { | ||
| 180 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 182 | |||
| 183 | if (False(capability & (Capability::Application | Capability::System))) { | ||
| 184 | LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability); | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | |||
| 188 | // TODO(ogniK): Recovery flag initialization for pctl:r | ||
| 189 | |||
| 190 | const auto tid = system.GetApplicationProcessProgramID(); | ||
| 191 | if (tid != 0) { | ||
| 192 | const FileSys::PatchManager pm{tid, system.GetFileSystemController(), | ||
| 193 | system.GetContentProvider()}; | ||
| 194 | const auto control = pm.GetControlMetadata(); | ||
| 195 | if (control.first) { | ||
| 196 | states.tid_from_event = 0; | ||
| 197 | states.launch_time_valid = false; | ||
| 198 | states.is_suspended = false; | ||
| 199 | states.free_communication = false; | ||
| 200 | states.stereo_vision = false; | ||
| 201 | states.application_info = ApplicationInfo{ | ||
| 202 | .application_id = tid, | ||
| 203 | .age_rating = control.first->GetRatingAge(), | ||
| 204 | .parental_control_flag = control.first->GetParentalControlFlag(), | ||
| 205 | .capability = capability, | ||
| 206 | }; | ||
| 207 | |||
| 208 | if (False(capability & (Capability::System | Capability::Recovery))) { | ||
| 209 | // TODO(ogniK): Signal application launch event | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | rb.Push(ResultSuccess); | ||
| 215 | } | ||
| 216 | |||
| 217 | void IParentalControlService::CheckFreeCommunicationPermission(HLERequestContext& ctx) { | ||
| 218 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 219 | |||
| 220 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 221 | if (!CheckFreeCommunicationPermissionImpl()) { | ||
| 222 | rb.Push(PCTL::ResultNoFreeCommunication); | ||
| 223 | } else { | ||
| 224 | rb.Push(ResultSuccess); | ||
| 225 | } | ||
| 226 | |||
| 227 | states.free_communication = true; | ||
| 228 | } | ||
| 229 | |||
| 230 | void IParentalControlService::ConfirmSnsPostPermission(HLERequestContext& ctx) { | ||
| 231 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 232 | |||
| 233 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 234 | rb.Push(PCTL::ResultNoFreeCommunication); | ||
| 235 | } | ||
| 236 | |||
| 237 | void IParentalControlService::IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) { | ||
| 238 | const bool is_temporary_unlocked = false; | ||
| 239 | |||
| 240 | LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}", is_temporary_unlocked); | ||
| 241 | |||
| 242 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 243 | rb.Push(ResultSuccess); | ||
| 244 | rb.Push<u8>(is_temporary_unlocked); | ||
| 245 | } | ||
| 246 | |||
| 247 | void IParentalControlService::ConfirmStereoVisionPermission(HLERequestContext& ctx) { | ||
| 248 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 249 | states.stereo_vision = true; | ||
| 250 | |||
| 251 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 252 | rb.Push(ResultSuccess); | ||
| 253 | } | ||
| 254 | |||
| 255 | void IParentalControlService::EndFreeCommunication(HLERequestContext& ctx) { | ||
| 256 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 257 | |||
| 258 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 259 | rb.Push(ResultSuccess); | ||
| 260 | } | ||
| 261 | |||
| 262 | void IParentalControlService::IsFreeCommunicationAvailable(HLERequestContext& ctx) { | ||
| 263 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 264 | |||
| 265 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 266 | if (!CheckFreeCommunicationPermissionImpl()) { | ||
| 267 | rb.Push(PCTL::ResultNoFreeCommunication); | ||
| 268 | } else { | ||
| 269 | rb.Push(ResultSuccess); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | void IParentalControlService::IsRestrictionEnabled(HLERequestContext& ctx) { | ||
| 274 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 275 | |||
| 276 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 277 | if (False(capability & (Capability::Status | Capability::Recovery))) { | ||
| 278 | LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!"); | ||
| 279 | rb.Push(PCTL::ResultNoCapability); | ||
| 280 | rb.Push(false); | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | |||
| 284 | rb.Push(pin_code[0] != '\0'); | ||
| 285 | } | ||
| 286 | |||
| 287 | void IParentalControlService::GetSafetyLevel(HLERequestContext& ctx) { | ||
| 288 | const u32 safety_level = 0; | ||
| 289 | |||
| 290 | LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level); | ||
| 291 | |||
| 292 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 293 | rb.Push(ResultSuccess); | ||
| 294 | rb.Push(safety_level); | ||
| 295 | } | ||
| 296 | |||
| 297 | void IParentalControlService::GetCurrentSettings(HLERequestContext& ctx) { | ||
| 298 | LOG_INFO(Service_PCTL, "called"); | ||
| 299 | |||
| 300 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 301 | rb.Push(ResultSuccess); | ||
| 302 | rb.PushRaw(restriction_settings); | ||
| 303 | } | ||
| 304 | |||
| 305 | void IParentalControlService::GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) { | ||
| 306 | const u32 count = 4; | ||
| 307 | |||
| 308 | LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count); | ||
| 309 | |||
| 310 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 311 | rb.Push(ResultSuccess); | ||
| 312 | rb.Push(count); | ||
| 313 | } | ||
| 314 | |||
| 315 | void IParentalControlService::ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) { | ||
| 316 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 317 | |||
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 319 | |||
| 320 | if (False(capability & Capability::StereoVision)) { | ||
| 321 | LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); | ||
| 322 | rb.Push(PCTL::ResultNoCapability); | ||
| 323 | return; | ||
| 324 | } | ||
| 325 | |||
| 326 | if (pin_code[0] == '\0') { | ||
| 327 | rb.Push(PCTL::ResultNoRestrictionEnabled); | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | |||
| 331 | rb.Push(ResultSuccess); | ||
| 332 | } | ||
| 333 | |||
| 334 | void IParentalControlService::IsStereoVisionPermitted(HLERequestContext& ctx) { | ||
| 335 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 336 | |||
| 337 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 338 | if (!ConfirmStereoVisionPermissionImpl()) { | ||
| 339 | rb.Push(PCTL::ResultStereoVisionRestricted); | ||
| 340 | rb.Push(false); | ||
| 341 | } else { | ||
| 342 | rb.Push(ResultSuccess); | ||
| 343 | rb.Push(true); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | void IParentalControlService::IsPairingActive(HLERequestContext& ctx) { | ||
| 348 | const bool is_pairing_active = false; | ||
| 349 | |||
| 350 | LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active); | ||
| 351 | |||
| 352 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 353 | rb.Push(ResultSuccess); | ||
| 354 | rb.Push<u8>(is_pairing_active); | ||
| 355 | } | ||
| 356 | |||
| 357 | void IParentalControlService::GetSynchronizationEvent(HLERequestContext& ctx) { | ||
| 358 | LOG_INFO(Service_PCTL, "called"); | ||
| 359 | |||
| 360 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 361 | rb.Push(ResultSuccess); | ||
| 362 | rb.PushCopyObjects(synchronization_event->GetReadableEvent()); | ||
| 363 | } | ||
| 364 | |||
| 365 | void IParentalControlService::GetPlayTimerSettings(HLERequestContext& ctx) { | ||
| 366 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 367 | |||
| 368 | const PlayTimerSettings timer_settings{}; | ||
| 369 | |||
| 370 | IPC::ResponseBuilder rb{ctx, 15}; | ||
| 371 | rb.Push(ResultSuccess); | ||
| 372 | rb.PushRaw(timer_settings); | ||
| 373 | } | ||
| 374 | |||
| 375 | void IParentalControlService::GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) { | ||
| 376 | LOG_INFO(Service_PCTL, "called"); | ||
| 377 | |||
| 378 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 379 | rb.Push(ResultSuccess); | ||
| 380 | rb.PushCopyObjects(request_suspension_event->GetReadableEvent()); | ||
| 381 | } | ||
| 382 | |||
| 383 | void IParentalControlService::IsPlayTimerAlarmDisabled(HLERequestContext& ctx) { | ||
| 384 | const bool is_play_timer_alarm_disabled = false; | ||
| 385 | |||
| 386 | LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}", is_play_timer_alarm_disabled); | ||
| 387 | |||
| 388 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 389 | rb.Push(ResultSuccess); | ||
| 390 | rb.Push<u8>(is_play_timer_alarm_disabled); | ||
| 391 | } | ||
| 392 | |||
| 393 | void IParentalControlService::GetUnlinkedEvent(HLERequestContext& ctx) { | ||
| 394 | LOG_INFO(Service_PCTL, "called"); | ||
| 395 | |||
| 396 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 397 | rb.Push(ResultSuccess); | ||
| 398 | rb.PushCopyObjects(unlinked_event->GetReadableEvent()); | ||
| 399 | } | ||
| 400 | |||
| 401 | void IParentalControlService::SetStereoVisionRestriction(HLERequestContext& ctx) { | ||
| 402 | IPC::RequestParser rp{ctx}; | ||
| 403 | const auto can_use = rp.Pop<bool>(); | ||
| 404 | LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use); | ||
| 405 | |||
| 406 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 407 | if (False(capability & Capability::StereoVision)) { | ||
| 408 | LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); | ||
| 409 | rb.Push(PCTL::ResultNoCapability); | ||
| 410 | return; | ||
| 411 | } | ||
| 412 | |||
| 413 | SetStereoVisionRestrictionImpl(can_use); | ||
| 414 | rb.Push(ResultSuccess); | ||
| 415 | } | ||
| 416 | |||
| 417 | void IParentalControlService::GetStereoVisionRestriction(HLERequestContext& ctx) { | ||
| 418 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 419 | |||
| 420 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 421 | if (False(capability & Capability::StereoVision)) { | ||
| 422 | LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); | ||
| 423 | rb.Push(PCTL::ResultNoCapability); | ||
| 424 | rb.Push(false); | ||
| 425 | return; | ||
| 426 | } | ||
| 427 | |||
| 428 | rb.Push(ResultSuccess); | ||
| 429 | rb.Push(settings.is_stero_vision_restricted); | ||
| 430 | } | ||
| 431 | |||
| 432 | void IParentalControlService::ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) { | ||
| 433 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 434 | |||
| 435 | states.stereo_vision = false; | ||
| 436 | |||
| 437 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 438 | rb.Push(ResultSuccess); | ||
| 439 | } | ||
| 440 | |||
| 441 | } // namespace Service::PCTL | ||
diff --git a/src/core/hle/service/pctl/parental_control_service.h b/src/core/hle/service/pctl/parental_control_service.h new file mode 100644 index 000000000..dcc357f65 --- /dev/null +++ b/src/core/hle/service/pctl/parental_control_service.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/kernel_helpers.h" | ||
| 7 | #include "core/hle/service/pctl/pctl_types.h" | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Service::PCTL { | ||
| 11 | |||
| 12 | class IParentalControlService final : public ServiceFramework<IParentalControlService> { | ||
| 13 | public: | ||
| 14 | explicit IParentalControlService(Core::System& system_, Capability capability_); | ||
| 15 | ~IParentalControlService() override; | ||
| 16 | |||
| 17 | private: | ||
| 18 | bool CheckFreeCommunicationPermissionImpl() const; | ||
| 19 | bool ConfirmStereoVisionPermissionImpl() const; | ||
| 20 | void SetStereoVisionRestrictionImpl(bool is_restricted); | ||
| 21 | |||
| 22 | void Initialize(HLERequestContext& ctx); | ||
| 23 | void CheckFreeCommunicationPermission(HLERequestContext& ctx); | ||
| 24 | void ConfirmSnsPostPermission(HLERequestContext& ctx); | ||
| 25 | void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx); | ||
| 26 | void ConfirmStereoVisionPermission(HLERequestContext& ctx); | ||
| 27 | void EndFreeCommunication(HLERequestContext& ctx); | ||
| 28 | void IsFreeCommunicationAvailable(HLERequestContext& ctx); | ||
| 29 | void IsRestrictionEnabled(HLERequestContext& ctx); | ||
| 30 | void GetSafetyLevel(HLERequestContext& ctx); | ||
| 31 | void GetCurrentSettings(HLERequestContext& ctx); | ||
| 32 | void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx); | ||
| 33 | void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx); | ||
| 34 | void IsStereoVisionPermitted(HLERequestContext& ctx); | ||
| 35 | void IsPairingActive(HLERequestContext& ctx); | ||
| 36 | void GetSynchronizationEvent(HLERequestContext& ctx); | ||
| 37 | void GetPlayTimerSettings(HLERequestContext& ctx); | ||
| 38 | void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx); | ||
| 39 | void IsPlayTimerAlarmDisabled(HLERequestContext& ctx); | ||
| 40 | void GetUnlinkedEvent(HLERequestContext& ctx); | ||
| 41 | void SetStereoVisionRestriction(HLERequestContext& ctx); | ||
| 42 | void GetStereoVisionRestriction(HLERequestContext& ctx); | ||
| 43 | void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx); | ||
| 44 | |||
| 45 | struct States { | ||
| 46 | u64 current_tid{}; | ||
| 47 | ApplicationInfo application_info{}; | ||
| 48 | u64 tid_from_event{}; | ||
| 49 | bool launch_time_valid{}; | ||
| 50 | bool is_suspended{}; | ||
| 51 | bool temporary_unlocked{}; | ||
| 52 | bool free_communication{}; | ||
| 53 | bool stereo_vision{}; | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct ParentalControlSettings { | ||
| 57 | bool is_stero_vision_restricted{}; | ||
| 58 | bool is_free_communication_default_on{}; | ||
| 59 | bool disabled{}; | ||
| 60 | }; | ||
| 61 | |||
| 62 | States states{}; | ||
| 63 | ParentalControlSettings settings{}; | ||
| 64 | RestrictionSettings restriction_settings{}; | ||
| 65 | std::array<char, 8> pin_code{}; | ||
| 66 | Capability capability{}; | ||
| 67 | |||
| 68 | Kernel::KEvent* synchronization_event; | ||
| 69 | Kernel::KEvent* unlinked_event; | ||
| 70 | Kernel::KEvent* request_suspension_event; | ||
| 71 | KernelHelpers::ServiceContext service_context; | ||
| 72 | }; | ||
| 73 | |||
| 74 | } // namespace Service::PCTL | ||
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp index dab37cdc4..118856574 100644 --- a/src/core/hle/service/pctl/pctl_module.cpp +++ b/src/core/hle/service/pctl/pctl_module.cpp | |||
| @@ -2,481 +2,15 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/logging/log.h" | 4 | #include "common/logging/log.h" |
| 5 | #include "core/core.h" | ||
| 6 | #include "core/file_sys/control_metadata.h" | ||
| 7 | #include "core/file_sys/patch_manager.h" | ||
| 8 | #include "core/hle/service/ipc_helpers.h" | 5 | #include "core/hle/service/ipc_helpers.h" |
| 9 | #include "core/hle/service/kernel_helpers.h" | 6 | #include "core/hle/service/kernel_helpers.h" |
| 7 | #include "core/hle/service/pctl/parental_control_service.h" | ||
| 10 | #include "core/hle/service/pctl/pctl.h" | 8 | #include "core/hle/service/pctl/pctl.h" |
| 11 | #include "core/hle/service/pctl/pctl_module.h" | 9 | #include "core/hle/service/pctl/pctl_module.h" |
| 12 | #include "core/hle/service/pctl/pctl_results.h" | ||
| 13 | #include "core/hle/service/pctl/pctl_types.h" | ||
| 14 | #include "core/hle/service/server_manager.h" | 10 | #include "core/hle/service/server_manager.h" |
| 15 | 11 | ||
| 16 | namespace Service::PCTL { | 12 | namespace Service::PCTL { |
| 17 | 13 | ||
| 18 | struct States { | ||
| 19 | u64 current_tid{}; | ||
| 20 | ApplicationInfo application_info{}; | ||
| 21 | u64 tid_from_event{}; | ||
| 22 | bool launch_time_valid{}; | ||
| 23 | bool is_suspended{}; | ||
| 24 | bool temporary_unlocked{}; | ||
| 25 | bool free_communication{}; | ||
| 26 | bool stereo_vision{}; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct ParentalControlSettings { | ||
| 30 | bool is_stero_vision_restricted{}; | ||
| 31 | bool is_free_communication_default_on{}; | ||
| 32 | bool disabled{}; | ||
| 33 | }; | ||
| 34 | |||
| 35 | class IParentalControlService final : public ServiceFramework<IParentalControlService> { | ||
| 36 | public: | ||
| 37 | explicit IParentalControlService(Core::System& system_, Capability capability_) | ||
| 38 | : ServiceFramework{system_, "IParentalControlService"}, capability{capability_}, | ||
| 39 | service_context{system_, "IParentalControlService"} { | ||
| 40 | // clang-format off | ||
| 41 | static const FunctionInfo functions[] = { | ||
| 42 | {1, &IParentalControlService::Initialize, "Initialize"}, | ||
| 43 | {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, | ||
| 44 | {1002, nullptr, "ConfirmLaunchApplicationPermission"}, | ||
| 45 | {1003, nullptr, "ConfirmResumeApplicationPermission"}, | ||
| 46 | {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"}, | ||
| 47 | {1005, nullptr, "ConfirmSystemSettingsPermission"}, | ||
| 48 | {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"}, | ||
| 49 | {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, | ||
| 50 | {1008, nullptr, "EnterRestrictedSystemSettings"}, | ||
| 51 | {1009, nullptr, "LeaveRestrictedSystemSettings"}, | ||
| 52 | {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, | ||
| 53 | {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, | ||
| 54 | {1012, nullptr, "GetRestrictedFeatures"}, | ||
| 55 | {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"}, | ||
| 56 | {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, | ||
| 57 | {1015, nullptr, "ConfirmPlayableApplicationVideo"}, | ||
| 58 | {1016, nullptr, "ConfirmShowNewsPermission"}, | ||
| 59 | {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"}, | ||
| 60 | {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"}, | ||
| 61 | {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"}, | ||
| 62 | {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"}, | ||
| 63 | {1033, nullptr, "SetSafetyLevel"}, | ||
| 64 | {1034, nullptr, "GetSafetyLevelSettings"}, | ||
| 65 | {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"}, | ||
| 66 | {1036, nullptr, "SetCustomSafetyLevelSettings"}, | ||
| 67 | {1037, nullptr, "GetDefaultRatingOrganization"}, | ||
| 68 | {1038, nullptr, "SetDefaultRatingOrganization"}, | ||
| 69 | {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"}, | ||
| 70 | {1042, nullptr, "AddToFreeCommunicationApplicationList"}, | ||
| 71 | {1043, nullptr, "DeleteSettings"}, | ||
| 72 | {1044, nullptr, "GetFreeCommunicationApplicationList"}, | ||
| 73 | {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, | ||
| 74 | {1046, nullptr, "DisableFeaturesForReset"}, | ||
| 75 | {1047, nullptr, "NotifyApplicationDownloadStarted"}, | ||
| 76 | {1048, nullptr, "NotifyNetworkProfileCreated"}, | ||
| 77 | {1049, nullptr, "ResetFreeCommunicationApplicationList"}, | ||
| 78 | {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, | ||
| 79 | {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, | ||
| 80 | {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, | ||
| 81 | {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"}, | ||
| 82 | {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"}, | ||
| 83 | {1201, nullptr, "UnlockRestrictionTemporarily"}, | ||
| 84 | {1202, nullptr, "UnlockSystemSettingsRestriction"}, | ||
| 85 | {1203, nullptr, "SetPinCode"}, | ||
| 86 | {1204, nullptr, "GenerateInquiryCode"}, | ||
| 87 | {1205, nullptr, "CheckMasterKey"}, | ||
| 88 | {1206, nullptr, "GetPinCodeLength"}, | ||
| 89 | {1207, nullptr, "GetPinCodeChangedEvent"}, | ||
| 90 | {1208, nullptr, "GetPinCode"}, | ||
| 91 | {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"}, | ||
| 92 | {1406, nullptr, "GetSettingsLastUpdated"}, | ||
| 93 | {1411, nullptr, "GetPairingAccountInfo"}, | ||
| 94 | {1421, nullptr, "GetAccountNickname"}, | ||
| 95 | {1424, nullptr, "GetAccountState"}, | ||
| 96 | {1425, nullptr, "RequestPostEvents"}, | ||
| 97 | {1426, nullptr, "GetPostEventInterval"}, | ||
| 98 | {1427, nullptr, "SetPostEventInterval"}, | ||
| 99 | {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"}, | ||
| 100 | {1451, nullptr, "StartPlayTimer"}, | ||
| 101 | {1452, nullptr, "StopPlayTimer"}, | ||
| 102 | {1453, nullptr, "IsPlayTimerEnabled"}, | ||
| 103 | {1454, nullptr, "GetPlayTimerRemainingTime"}, | ||
| 104 | {1455, nullptr, "IsRestrictedByPlayTimer"}, | ||
| 105 | {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"}, | ||
| 106 | {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"}, | ||
| 107 | {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"}, | ||
| 108 | {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"}, | ||
| 109 | {1472, nullptr, "CancelNetworkRequest"}, | ||
| 110 | {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"}, | ||
| 111 | {1474, nullptr, "ClearUnlinkedEvent"}, | ||
| 112 | {1601, nullptr, "DisableAllFeatures"}, | ||
| 113 | {1602, nullptr, "PostEnableAllFeatures"}, | ||
| 114 | {1603, nullptr, "IsAllFeaturesDisabled"}, | ||
| 115 | {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"}, | ||
| 116 | {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"}, | ||
| 117 | {1903, nullptr, "GetExemptApplicationListCountForDebug"}, | ||
| 118 | {1904, nullptr, "GetExemptApplicationListForDebug"}, | ||
| 119 | {1905, nullptr, "UpdateExemptApplicationListForDebug"}, | ||
| 120 | {1906, nullptr, "AddToExemptApplicationListForDebug"}, | ||
| 121 | {1907, nullptr, "DeleteFromExemptApplicationListForDebug"}, | ||
| 122 | {1908, nullptr, "ClearExemptApplicationListForDebug"}, | ||
| 123 | {1941, nullptr, "DeletePairing"}, | ||
| 124 | {1951, nullptr, "SetPlayTimerSettingsForDebug"}, | ||
| 125 | {1952, nullptr, "GetPlayTimerSpentTimeForTest"}, | ||
| 126 | {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"}, | ||
| 127 | {2001, nullptr, "RequestPairingAsync"}, | ||
| 128 | {2002, nullptr, "FinishRequestPairing"}, | ||
| 129 | {2003, nullptr, "AuthorizePairingAsync"}, | ||
| 130 | {2004, nullptr, "FinishAuthorizePairing"}, | ||
| 131 | {2005, nullptr, "RetrievePairingInfoAsync"}, | ||
| 132 | {2006, nullptr, "FinishRetrievePairingInfo"}, | ||
| 133 | {2007, nullptr, "UnlinkPairingAsync"}, | ||
| 134 | {2008, nullptr, "FinishUnlinkPairing"}, | ||
| 135 | {2009, nullptr, "GetAccountMiiImageAsync"}, | ||
| 136 | {2010, nullptr, "FinishGetAccountMiiImage"}, | ||
| 137 | {2011, nullptr, "GetAccountMiiImageContentTypeAsync"}, | ||
| 138 | {2012, nullptr, "FinishGetAccountMiiImageContentType"}, | ||
| 139 | {2013, nullptr, "SynchronizeParentalControlSettingsAsync"}, | ||
| 140 | {2014, nullptr, "FinishSynchronizeParentalControlSettings"}, | ||
| 141 | {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, | ||
| 142 | {2016, nullptr, "RequestUpdateExemptionListAsync"}, | ||
| 143 | }; | ||
| 144 | // clang-format on | ||
| 145 | RegisterHandlers(functions); | ||
| 146 | |||
| 147 | synchronization_event = | ||
| 148 | service_context.CreateEvent("IParentalControlService::SynchronizationEvent"); | ||
| 149 | unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent"); | ||
| 150 | request_suspension_event = | ||
| 151 | service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent"); | ||
| 152 | } | ||
| 153 | |||
| 154 | ~IParentalControlService() { | ||
| 155 | service_context.CloseEvent(synchronization_event); | ||
| 156 | service_context.CloseEvent(unlinked_event); | ||
| 157 | service_context.CloseEvent(request_suspension_event); | ||
| 158 | }; | ||
| 159 | |||
| 160 | private: | ||
| 161 | bool CheckFreeCommunicationPermissionImpl() const { | ||
| 162 | if (states.temporary_unlocked) { | ||
| 163 | return true; | ||
| 164 | } | ||
| 165 | if ((states.application_info.parental_control_flag & 1) == 0) { | ||
| 166 | return true; | ||
| 167 | } | ||
| 168 | if (pin_code[0] == '\0') { | ||
| 169 | return true; | ||
| 170 | } | ||
| 171 | if (!settings.is_free_communication_default_on) { | ||
| 172 | return true; | ||
| 173 | } | ||
| 174 | // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here | ||
| 175 | // but as we don't have multiproceses support yet, we can just assume our application is | ||
| 176 | // valid for the time being | ||
| 177 | return true; | ||
| 178 | } | ||
| 179 | |||
| 180 | bool ConfirmStereoVisionPermissionImpl() const { | ||
| 181 | if (states.temporary_unlocked) { | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | if (pin_code[0] == '\0') { | ||
| 185 | return true; | ||
| 186 | } | ||
| 187 | if (!settings.is_stero_vision_restricted) { | ||
| 188 | return false; | ||
| 189 | } | ||
| 190 | return true; | ||
| 191 | } | ||
| 192 | |||
| 193 | void SetStereoVisionRestrictionImpl(bool is_restricted) { | ||
| 194 | if (settings.disabled) { | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (pin_code[0] == '\0') { | ||
| 199 | return; | ||
| 200 | } | ||
| 201 | settings.is_stero_vision_restricted = is_restricted; | ||
| 202 | } | ||
| 203 | |||
| 204 | void Initialize(HLERequestContext& ctx) { | ||
| 205 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 206 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 207 | |||
| 208 | if (False(capability & (Capability::Application | Capability::System))) { | ||
| 209 | LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability); | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | |||
| 213 | // TODO(ogniK): Recovery flag initialization for pctl:r | ||
| 214 | |||
| 215 | const auto tid = system.GetApplicationProcessProgramID(); | ||
| 216 | if (tid != 0) { | ||
| 217 | const FileSys::PatchManager pm{tid, system.GetFileSystemController(), | ||
| 218 | system.GetContentProvider()}; | ||
| 219 | const auto control = pm.GetControlMetadata(); | ||
| 220 | if (control.first) { | ||
| 221 | states.tid_from_event = 0; | ||
| 222 | states.launch_time_valid = false; | ||
| 223 | states.is_suspended = false; | ||
| 224 | states.free_communication = false; | ||
| 225 | states.stereo_vision = false; | ||
| 226 | states.application_info = ApplicationInfo{ | ||
| 227 | .application_id = tid, | ||
| 228 | .age_rating = control.first->GetRatingAge(), | ||
| 229 | .parental_control_flag = control.first->GetParentalControlFlag(), | ||
| 230 | .capability = capability, | ||
| 231 | }; | ||
| 232 | |||
| 233 | if (False(capability & (Capability::System | Capability::Recovery))) { | ||
| 234 | // TODO(ogniK): Signal application launch event | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | rb.Push(ResultSuccess); | ||
| 240 | } | ||
| 241 | |||
| 242 | void CheckFreeCommunicationPermission(HLERequestContext& ctx) { | ||
| 243 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 244 | |||
| 245 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 246 | if (!CheckFreeCommunicationPermissionImpl()) { | ||
| 247 | rb.Push(ResultNoFreeCommunication); | ||
| 248 | } else { | ||
| 249 | rb.Push(ResultSuccess); | ||
| 250 | } | ||
| 251 | |||
| 252 | states.free_communication = true; | ||
| 253 | } | ||
| 254 | |||
| 255 | void ConfirmSnsPostPermission(HLERequestContext& ctx) { | ||
| 256 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 257 | |||
| 258 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 259 | rb.Push(ResultNoFreeCommunication); | ||
| 260 | } | ||
| 261 | |||
| 262 | void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) { | ||
| 263 | const bool is_temporary_unlocked = false; | ||
| 264 | |||
| 265 | LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}", | ||
| 266 | is_temporary_unlocked); | ||
| 267 | |||
| 268 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 269 | rb.Push(ResultSuccess); | ||
| 270 | rb.Push<u8>(is_temporary_unlocked); | ||
| 271 | } | ||
| 272 | |||
| 273 | void ConfirmStereoVisionPermission(HLERequestContext& ctx) { | ||
| 274 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 275 | states.stereo_vision = true; | ||
| 276 | |||
| 277 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 278 | rb.Push(ResultSuccess); | ||
| 279 | } | ||
| 280 | |||
| 281 | void EndFreeCommunication(HLERequestContext& ctx) { | ||
| 282 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 283 | |||
| 284 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 285 | rb.Push(ResultSuccess); | ||
| 286 | } | ||
| 287 | |||
| 288 | void IsFreeCommunicationAvailable(HLERequestContext& ctx) { | ||
| 289 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 290 | |||
| 291 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 292 | if (!CheckFreeCommunicationPermissionImpl()) { | ||
| 293 | rb.Push(ResultNoFreeCommunication); | ||
| 294 | } else { | ||
| 295 | rb.Push(ResultSuccess); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | void IsRestrictionEnabled(HLERequestContext& ctx) { | ||
| 300 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 301 | |||
| 302 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 303 | if (False(capability & (Capability::Status | Capability::Recovery))) { | ||
| 304 | LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!"); | ||
| 305 | rb.Push(ResultNoCapability); | ||
| 306 | rb.Push(false); | ||
| 307 | return; | ||
| 308 | } | ||
| 309 | |||
| 310 | rb.Push(pin_code[0] != '\0'); | ||
| 311 | } | ||
| 312 | |||
| 313 | void GetSafetyLevel(HLERequestContext& ctx) { | ||
| 314 | const u32 safety_level = 0; | ||
| 315 | |||
| 316 | LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level); | ||
| 317 | |||
| 318 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 319 | rb.Push(ResultSuccess); | ||
| 320 | rb.Push(safety_level); | ||
| 321 | } | ||
| 322 | |||
| 323 | void GetCurrentSettings(HLERequestContext& ctx) { | ||
| 324 | LOG_INFO(Service_PCTL, "called"); | ||
| 325 | |||
| 326 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 327 | rb.Push(ResultSuccess); | ||
| 328 | rb.PushRaw(restriction_settings); | ||
| 329 | } | ||
| 330 | |||
| 331 | void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) { | ||
| 332 | const u32 count = 4; | ||
| 333 | |||
| 334 | LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count); | ||
| 335 | |||
| 336 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 337 | rb.Push(ResultSuccess); | ||
| 338 | rb.Push(count); | ||
| 339 | } | ||
| 340 | |||
| 341 | void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) { | ||
| 342 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 343 | |||
| 344 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 345 | |||
| 346 | if (False(capability & Capability::StereoVision)) { | ||
| 347 | LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); | ||
| 348 | rb.Push(ResultNoCapability); | ||
| 349 | return; | ||
| 350 | } | ||
| 351 | |||
| 352 | if (pin_code[0] == '\0') { | ||
| 353 | rb.Push(ResultNoRestrictionEnabled); | ||
| 354 | return; | ||
| 355 | } | ||
| 356 | |||
| 357 | rb.Push(ResultSuccess); | ||
| 358 | } | ||
| 359 | |||
| 360 | void IsStereoVisionPermitted(HLERequestContext& ctx) { | ||
| 361 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 362 | |||
| 363 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 364 | if (!ConfirmStereoVisionPermissionImpl()) { | ||
| 365 | rb.Push(ResultStereoVisionRestricted); | ||
| 366 | rb.Push(false); | ||
| 367 | } else { | ||
| 368 | rb.Push(ResultSuccess); | ||
| 369 | rb.Push(true); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | void IsPairingActive(HLERequestContext& ctx) { | ||
| 374 | const bool is_pairing_active = false; | ||
| 375 | |||
| 376 | LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active); | ||
| 377 | |||
| 378 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 379 | rb.Push(ResultSuccess); | ||
| 380 | rb.Push<u8>(is_pairing_active); | ||
| 381 | } | ||
| 382 | |||
| 383 | void GetSynchronizationEvent(HLERequestContext& ctx) { | ||
| 384 | LOG_INFO(Service_PCTL, "called"); | ||
| 385 | |||
| 386 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 387 | rb.Push(ResultSuccess); | ||
| 388 | rb.PushCopyObjects(synchronization_event->GetReadableEvent()); | ||
| 389 | } | ||
| 390 | |||
| 391 | void GetPlayTimerSettings(HLERequestContext& ctx) { | ||
| 392 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 393 | |||
| 394 | const PlayTimerSettings timer_settings{}; | ||
| 395 | |||
| 396 | IPC::ResponseBuilder rb{ctx, 15}; | ||
| 397 | rb.Push(ResultSuccess); | ||
| 398 | rb.PushRaw(timer_settings); | ||
| 399 | } | ||
| 400 | |||
| 401 | void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) { | ||
| 402 | LOG_INFO(Service_PCTL, "called"); | ||
| 403 | |||
| 404 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 405 | rb.Push(ResultSuccess); | ||
| 406 | rb.PushCopyObjects(request_suspension_event->GetReadableEvent()); | ||
| 407 | } | ||
| 408 | |||
| 409 | void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) { | ||
| 410 | const bool is_play_timer_alarm_disabled = false; | ||
| 411 | |||
| 412 | LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}", | ||
| 413 | is_play_timer_alarm_disabled); | ||
| 414 | |||
| 415 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 416 | rb.Push(ResultSuccess); | ||
| 417 | rb.Push<u8>(is_play_timer_alarm_disabled); | ||
| 418 | } | ||
| 419 | |||
| 420 | void GetUnlinkedEvent(HLERequestContext& ctx) { | ||
| 421 | LOG_INFO(Service_PCTL, "called"); | ||
| 422 | |||
| 423 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 424 | rb.Push(ResultSuccess); | ||
| 425 | rb.PushCopyObjects(unlinked_event->GetReadableEvent()); | ||
| 426 | } | ||
| 427 | |||
| 428 | void SetStereoVisionRestriction(HLERequestContext& ctx) { | ||
| 429 | IPC::RequestParser rp{ctx}; | ||
| 430 | const auto can_use = rp.Pop<bool>(); | ||
| 431 | LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use); | ||
| 432 | |||
| 433 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 434 | if (False(capability & Capability::StereoVision)) { | ||
| 435 | LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); | ||
| 436 | rb.Push(ResultNoCapability); | ||
| 437 | return; | ||
| 438 | } | ||
| 439 | |||
| 440 | SetStereoVisionRestrictionImpl(can_use); | ||
| 441 | rb.Push(ResultSuccess); | ||
| 442 | } | ||
| 443 | |||
| 444 | void GetStereoVisionRestriction(HLERequestContext& ctx) { | ||
| 445 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 446 | |||
| 447 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 448 | if (False(capability & Capability::StereoVision)) { | ||
| 449 | LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); | ||
| 450 | rb.Push(ResultNoCapability); | ||
| 451 | rb.Push(false); | ||
| 452 | return; | ||
| 453 | } | ||
| 454 | |||
| 455 | rb.Push(ResultSuccess); | ||
| 456 | rb.Push(settings.is_stero_vision_restricted); | ||
| 457 | } | ||
| 458 | |||
| 459 | void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) { | ||
| 460 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 461 | |||
| 462 | states.stereo_vision = false; | ||
| 463 | |||
| 464 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 465 | rb.Push(ResultSuccess); | ||
| 466 | } | ||
| 467 | |||
| 468 | States states{}; | ||
| 469 | ParentalControlSettings settings{}; | ||
| 470 | RestrictionSettings restriction_settings{}; | ||
| 471 | std::array<char, 8> pin_code{}; | ||
| 472 | Capability capability{}; | ||
| 473 | |||
| 474 | Kernel::KEvent* synchronization_event; | ||
| 475 | Kernel::KEvent* unlinked_event; | ||
| 476 | Kernel::KEvent* request_suspension_event; | ||
| 477 | KernelHelpers::ServiceContext service_context; | ||
| 478 | }; | ||
| 479 | |||
| 480 | void Module::Interface::CreateService(HLERequestContext& ctx) { | 14 | void Module::Interface::CreateService(HLERequestContext& ctx) { |
| 481 | LOG_DEBUG(Service_PCTL, "called"); | 15 | LOG_DEBUG(Service_PCTL, "called"); |
| 482 | 16 | ||