early-access version 1534
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 1533. | ||||
| This is the source code for early-access 1534. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const { | ||||
|     return raw.device_save_data_size; | ||||
| } | ||||
|  | ||||
| u32 NACP::GetParentalControlFlag() const { | ||||
|     return raw.parental_control; | ||||
| } | ||||
|  | ||||
| const std::array<u8, 0x20>& NACP::GetRatingAge() const { | ||||
|     return raw.rating_age; | ||||
| } | ||||
|  | ||||
| std::vector<u8> NACP::GetRawBytes() const { | ||||
|     std::vector<u8> out(sizeof(RawNACP)); | ||||
|     std::memcpy(out.data(), &raw, sizeof(RawNACP)); | ||||
|   | ||||
| @@ -114,6 +114,8 @@ public: | ||||
|     std::vector<u8> GetRawBytes() const; | ||||
|     bool GetUserAccountSwitchLock() const; | ||||
|     u64 GetDeviceSaveDataSize() const; | ||||
|     u32 GetParentalControlFlag() const; | ||||
|     const std::array<u8, 0x20>& GetRatingAge() const; | ||||
|  | ||||
| private: | ||||
|     RawNACP raw{}; | ||||
|   | ||||
| @@ -133,7 +133,7 @@ private: | ||||
|     void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) { | ||||
|         // This is safe to stub, as there should be no adverse consequences from reporting no | ||||
|         // blocked users. | ||||
|         LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||||
|         LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(0); // Indicates there are no blocked users | ||||
| @@ -141,14 +141,14 @@ private: | ||||
|  | ||||
|     void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) { | ||||
|         // Stub used by Splatoon 2 | ||||
|         LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||||
|         LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void UpdateUserPresence(Kernel::HLERequestContext& ctx) { | ||||
|         // Stub used by Retro City Rampage | ||||
|         LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||||
|         LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
| @@ -159,7 +159,7 @@ private: | ||||
|         const auto uuid = rp.PopRaw<Common::UUID>(); | ||||
|         [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); | ||||
|         const auto pid = rp.Pop<u64>(); | ||||
|         LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset, | ||||
|         LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset, | ||||
|                     uuid.Format(), pid); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
| @@ -191,7 +191,7 @@ public: | ||||
|  | ||||
| private: | ||||
|     void GetEvent(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_ACC, "called"); | ||||
|         LOG_DEBUG(Service_Friend, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
| @@ -199,7 +199,7 @@ private: | ||||
|     } | ||||
|  | ||||
|     void Clear(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_ACC, "called"); | ||||
|         LOG_DEBUG(Service_Friend, "called"); | ||||
|         while (!notifications.empty()) { | ||||
|             notifications.pop(); | ||||
|         } | ||||
| @@ -210,10 +210,10 @@ private: | ||||
|     } | ||||
|  | ||||
|     void Pop(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_ACC, "called"); | ||||
|         LOG_DEBUG(Service_Friend, "called"); | ||||
|  | ||||
|         if (notifications.empty()) { | ||||
|             LOG_ERROR(Service_ACC, "No notifications in queue!"); | ||||
|             LOG_ERROR(Service_Friend, "No notifications in queue!"); | ||||
|             IPC::ResponseBuilder rb{ctx, 2}; | ||||
|             rb.Push(ERR_NO_NOTIFICATIONS); | ||||
|             return; | ||||
| @@ -231,7 +231,8 @@ private: | ||||
|             break; | ||||
|         default: | ||||
|             // HOS seems not have an error case for an unknown notification | ||||
|             LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type); | ||||
|             LOG_WARNING(Service_Friend, "Unknown notification {:08X}", | ||||
|                         notification.notification_type); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @@ -269,14 +270,14 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushIpcInterface<IFriendService>(system); | ||||
|     LOG_DEBUG(Service_ACC, "called"); | ||||
|     LOG_DEBUG(Service_Friend, "called"); | ||||
| } | ||||
|  | ||||
| void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto uuid = rp.PopRaw<Common::UUID>(); | ||||
|  | ||||
|     LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format()); | ||||
|     LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format()); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #include <cstring> | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/hle/service/hid/controllers/gesture.h" | ||||
| @@ -19,9 +20,9 @@ Controller_Gesture::~Controller_Gesture() = default; | ||||
|  | ||||
| void Controller_Gesture::OnInit() { | ||||
|     for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||||
|         mouse_finger_id[id] = MAX_FINGERS; | ||||
|         keyboard_finger_id[id] = MAX_FINGERS; | ||||
|         udp_finger_id[id] = MAX_FINGERS; | ||||
|         mouse_finger_id[id] = MAX_POINTS; | ||||
|         keyboard_finger_id[id] = MAX_POINTS; | ||||
|         udp_finger_id[id] = MAX_POINTS; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -142,6 +143,10 @@ std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const { | ||||
| std::size_t Controller_Gesture::UpdateTouchInputEvent( | ||||
|     const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||||
|     const auto& [x, y, pressed] = touch_input; | ||||
|     if (finger_id > MAX_POINTS) { | ||||
|         LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); | ||||
|         return MAX_POINTS; | ||||
|     } | ||||
|     if (pressed) { | ||||
|         if (finger_id == MAX_POINTS) { | ||||
|             const auto first_free_id = GetUnusedFingerID(); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include <algorithm> | ||||
| #include <cstring> | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/frontend/input.h" | ||||
| @@ -118,6 +119,10 @@ std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { | ||||
| std::size_t Controller_Touchscreen::UpdateTouchInputEvent( | ||||
|     const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||||
|     const auto& [x, y, pressed] = touch_input; | ||||
|     if (finger_id > MAX_FINGERS) { | ||||
|         LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); | ||||
|         return MAX_FINGERS; | ||||
|     } | ||||
|     if (pressed) { | ||||
|         Attributes attribute{}; | ||||
|         if (finger_id == MAX_FINGERS) { | ||||
|   | ||||
| @@ -3,16 +3,30 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/control_metadata.h" | ||||
| #include "core/file_sys/patch_manager.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/service/pctl/module.h" | ||||
| #include "core/hle/service/pctl/pctl.h" | ||||
|  | ||||
| namespace Service::PCTL { | ||||
|  | ||||
| namespace Error { | ||||
|  | ||||
| constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101}; | ||||
| constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104}; | ||||
| constexpr ResultCode ResultNoCapatability{ErrorModule::PCTL, 131}; | ||||
| constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181}; | ||||
|  | ||||
| } // namespace Error | ||||
|  | ||||
| class IParentalControlService final : public ServiceFramework<IParentalControlService> { | ||||
| public: | ||||
|     explicit IParentalControlService(Core::System& system_) | ||||
|         : ServiceFramework{system_, "IParentalControlService"} { | ||||
|     explicit IParentalControlService(Core::System& system_, Capability capability) | ||||
|         : ServiceFramework{system_, "IParentalControlService"}, system(system_), | ||||
|           capability(capability) { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {1, &IParentalControlService::Initialize, "Initialize"}, | ||||
| @@ -28,13 +42,13 @@ public: | ||||
|             {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, | ||||
|             {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, | ||||
|             {1012, nullptr, "GetRestrictedFeatures"}, | ||||
|             {1013, nullptr, "ConfirmStereoVisionPermission"}, | ||||
|             {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"}, | ||||
|             {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, | ||||
|             {1015, nullptr, "ConfirmPlayableApplicationVideo"}, | ||||
|             {1016, nullptr, "ConfirmShowNewsPermission"}, | ||||
|             {1017, nullptr, "EndFreeCommunication"}, | ||||
|             {1018, nullptr, "IsFreeCommunicationAvailable"}, | ||||
|             {1031, nullptr, "IsRestrictionEnabled"}, | ||||
|             {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"}, | ||||
|             {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"}, | ||||
|             {1032, nullptr, "GetSafetyLevel"}, | ||||
|             {1033, nullptr, "SetSafetyLevel"}, | ||||
|             {1034, nullptr, "GetSafetyLevelSettings"}, | ||||
| @@ -119,62 +133,234 @@ public: | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void Initialize(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||||
|     bool CheckFreeCommunicationPermissionImpl() { | ||||
|         if (states.temporary_unlocked) { | ||||
|             return true; | ||||
|         } | ||||
|         if ((states.application_info.parental_control_flag & 1) == 0) { | ||||
|             return true; | ||||
|         } | ||||
|         if (pin_code[0] == '\0') { | ||||
|             return true; | ||||
|         } | ||||
|         if (!settings.is_free_communication_default_on) { | ||||
|             return true; | ||||
|         } | ||||
|         // TODO(ogniK): Check for blacklisted/exempted applications | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     bool ConfirmStereoVisionPermissionImpl() { | ||||
|         if (states.temporary_unlocked) { | ||||
|             return true; | ||||
|         } | ||||
|         if (pin_code[0] == '\0') { | ||||
|             return true; | ||||
|         } | ||||
|         if (!settings.is_stero_vision_restricted) { | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void SetStereoVisionRestrictionImpl(bool is_restricted) { | ||||
|         if (settings.disabled) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (pin_code[0] == '\0') { | ||||
|             return; | ||||
|         } | ||||
|         settings.is_stero_vision_restricted = is_restricted; | ||||
|     } | ||||
|  | ||||
|     void Initialize(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|  | ||||
|         if (False(capability & (Capability::Application | Capability::System))) { | ||||
|             LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", | ||||
|                       static_cast<s32>(capability)); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // TODO(ogniK): Recovery | ||||
|  | ||||
|         const auto tid = system.CurrentProcess()->GetTitleID(); | ||||
|         if (tid != 0) { | ||||
|             const FileSys::PatchManager pm{tid, system.GetFileSystemController(), | ||||
|                                            system.GetContentProvider()}; | ||||
|             const auto control = pm.GetControlMetadata(); | ||||
|             if (control.first) { | ||||
|                 states.tid_from_event = 0; | ||||
|                 states.launch_time_valid = false; | ||||
|                 states.is_suspended = false; | ||||
|                 states.free_communication = false; | ||||
|                 states.stereo_vision = false; | ||||
|                 states.application_info = ApplicationInfo{ | ||||
|                     .tid = tid, | ||||
|                     .age_rating = control.first->GetRatingAge(), | ||||
|                     .parental_control_flag = control.first->GetParentalControlFlag(), | ||||
|                     .capability = capability, | ||||
|                 }; | ||||
|  | ||||
|                 if (False(capability & (Capability::System | Capability::Recovery))) { | ||||
|                     // TODO(ogniK): Signal application launch event | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         if (!CheckFreeCommunicationPermissionImpl()) { | ||||
|             rb.Push(Error::ResultNoFreeCommunication); | ||||
|         } else { | ||||
|             rb.Push(RESULT_SUCCESS); | ||||
|         } | ||||
|  | ||||
|         states.free_communication = true; | ||||
|     } | ||||
|  | ||||
|     void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|         states.stereo_vision = true; | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { | ||||
|     void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         if (!CheckFreeCommunicationPermissionImpl()) { | ||||
|             rb.Push(Error::ResultNoFreeCommunication); | ||||
|         } else { | ||||
|             rb.Push(RESULT_SUCCESS); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         if (False(capability & (Capability::Status | Capability::Recovery))) { | ||||
|             LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!"); | ||||
|             rb.Push(Error::ResultNoCapatability); | ||||
|             rb.Push(false); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         rb.Push(pin_code[0] != '\0'); | ||||
|     } | ||||
|  | ||||
|     void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|  | ||||
|         if (False(capability & Capability::SteroVision)) { | ||||
|             LOG_ERROR(Service_PCTL, "Application does not have SteroVision capability!"); | ||||
|             rb.Push(Error::ResultNoCapatability); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (pin_code[0] == '\0') { | ||||
|             rb.Push(Error::ResultNoRestrictionEnabled); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push(true); | ||||
|         if (!ConfirmStereoVisionPermissionImpl()) { | ||||
|             rb.Push(Error::ResultStereoVisionRestricted); | ||||
|             rb.Push(false); | ||||
|         } else { | ||||
|             rb.Push(RESULT_SUCCESS); | ||||
|             rb.Push(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const auto can_use = rp.Pop<bool>(); | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use); | ||||
|  | ||||
|         can_use_stereo_vision = can_use; | ||||
|         LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         if (False(capability & Capability::SteroVision)) { | ||||
|             LOG_ERROR(Service_PCTL, "Application does not have SteroVision capability!"); | ||||
|             rb.Push(Error::ResultNoCapatability); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         SetStereoVisionRestrictionImpl(can_use); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         if (False(capability & Capability::SteroVision)) { | ||||
|             LOG_ERROR(Service_PCTL, "Application does not have SteroVision capability!"); | ||||
|             rb.Push(Error::ResultNoCapatability); | ||||
|             rb.Push(false); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push(can_use_stereo_vision); | ||||
|         rb.Push(settings.is_stero_vision_restricted); | ||||
|     } | ||||
|  | ||||
|     void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||||
|         LOG_DEBUG(Service_PCTL, "called"); | ||||
|  | ||||
|         states.stereo_vision = false; | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     struct ApplicationInfo { | ||||
|         u64 tid{}; | ||||
|         std::array<u8, 32> age_rating{}; | ||||
|         u32 parental_control_flag{}; | ||||
|         Capability capability{}; | ||||
|     }; | ||||
|  | ||||
|     struct States { | ||||
|         u64 current_tid{}; | ||||
|         ApplicationInfo application_info{}; | ||||
|         u64 tid_from_event{}; | ||||
|         bool launch_time_valid{}; | ||||
|         bool is_suspended{}; | ||||
|         bool temporary_unlocked{}; | ||||
|         bool free_communication{}; | ||||
|         bool stereo_vision{}; | ||||
|     }; | ||||
|  | ||||
|     struct ParentalControlSettings { | ||||
|         bool is_stero_vision_restricted{}; | ||||
|         bool is_free_communication_default_on{}; | ||||
|         bool disabled{}; | ||||
|     }; | ||||
|  | ||||
|     States states{}; | ||||
|     ParentalControlSettings settings{}; | ||||
|     std::array<char, 8> pin_code{}; | ||||
|     bool can_use_stereo_vision = true; | ||||
|     Core::System& system; | ||||
|     Capability capability{}; | ||||
| }; | ||||
|  | ||||
| void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | ||||
| @@ -182,7 +368,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushIpcInterface<IParentalControlService>(system); | ||||
|     // TODO(ogniK): Get TID from process | ||||
|  | ||||
|     rb.PushIpcInterface<IParentalControlService>(system, capability); | ||||
| } | ||||
|  | ||||
| void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { | ||||
| @@ -190,21 +378,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushIpcInterface<IParentalControlService>(system); | ||||
|     rb.PushIpcInterface<IParentalControlService>(system, capability); | ||||
| } | ||||
|  | ||||
| Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, | ||||
|                              const char* name) | ||||
|     : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||||
|                              const char* name, Capability capability) | ||||
|     : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {} | ||||
|  | ||||
| Module::Interface::~Interface() = default; | ||||
|  | ||||
| void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | ||||
|     auto module = std::make_shared<Module>(); | ||||
|     std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager); | ||||
|     std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager); | ||||
|     std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager); | ||||
|     std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager); | ||||
|     std::make_shared<PCTL>(system, module, "pctl", | ||||
|                            Capability::Application | Capability::SnsPost | Capability::Status | | ||||
|                                Capability::SteroVision) | ||||
|         ->InstallAsService(service_manager); | ||||
|     // TODO(ogniK): Implement remaining capabilities | ||||
|     std::make_shared<PCTL>(system, module, "pctl:a", Capability::None) | ||||
|         ->InstallAsService(service_manager); | ||||
|     std::make_shared<PCTL>(system, module, "pctl:r", Capability::None) | ||||
|         ->InstallAsService(service_manager); | ||||
|     std::make_shared<PCTL>(system, module, "pctl:s", Capability::None) | ||||
|         ->InstallAsService(service_manager); | ||||
| } | ||||
|  | ||||
| } // namespace Service::PCTL | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "common/common_funcs.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | ||||
| namespace Core { | ||||
| @@ -12,12 +13,23 @@ class System; | ||||
|  | ||||
| namespace Service::PCTL { | ||||
|  | ||||
| enum class Capability : s32 { | ||||
|     None = 0x0, | ||||
|     Application = 1 << 0, | ||||
|     SnsPost = 1 << 1, | ||||
|     Recovery = 1 << 6, | ||||
|     Status = 1 << 8, | ||||
|     SteroVision = 1 << 9, | ||||
|     System = 1 << 15, | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(Capability); | ||||
|  | ||||
| class Module final { | ||||
| public: | ||||
|     class Interface : public ServiceFramework<Interface> { | ||||
|     public: | ||||
|         explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, | ||||
|                            const char* name); | ||||
|         explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name, | ||||
|                            Capability capability); | ||||
|         ~Interface() override; | ||||
|  | ||||
|         void CreateService(Kernel::HLERequestContext& ctx); | ||||
| @@ -25,6 +37,9 @@ public: | ||||
|  | ||||
|     protected: | ||||
|         std::shared_ptr<Module> module; | ||||
|  | ||||
|     private: | ||||
|         Capability capability{}; | ||||
|     }; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -6,8 +6,9 @@ | ||||
|  | ||||
| namespace Service::PCTL { | ||||
|  | ||||
| PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name) | ||||
|     : Interface{system_, std::move(module_), name} { | ||||
| PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, | ||||
|            Capability capability) | ||||
|     : Interface{system_, std::move(module_), name, capability} { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &PCTL::CreateService, "CreateService"}, | ||||
|         {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, | ||||
|   | ||||
| @@ -14,7 +14,8 @@ namespace Service::PCTL { | ||||
|  | ||||
| class PCTL final : public Module::Interface { | ||||
| public: | ||||
|     explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name); | ||||
|     explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, | ||||
|                   Capability capability); | ||||
|     ~PCTL() override; | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user