summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authorGravatar liamwhite2024-02-24 12:48:26 -0500
committerGravatar GitHub2024-02-24 12:48:26 -0500
commitdcf7698924867dbf1fffd0e0cf9f91dd1f7323a9 (patch)
tree2556d5d884e8928bb322220035b319ad4708acfb /src/core/hle
parentMerge pull request #13150 from liamwhite/region (diff)
parentaoc: Rename AOC_U to IAddOnContentManager (diff)
downloadyuzu-dcf7698924867dbf1fffd0e0cf9f91dd1f7323a9.tar.gz
yuzu-dcf7698924867dbf1fffd0e0cf9f91dd1f7323a9.tar.xz
yuzu-dcf7698924867dbf1fffd0e0cf9f91dd1f7323a9.zip
Merge pull request #13081 from FearlessTobi/aoc-ipc
aoc: Migrate to use cmif serialization
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/aoc/addon_content_manager.cpp223
-rw-r--r--src/core/hle/service/aoc/addon_content_manager.h51
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp340
-rw-r--r--src/core/hle/service/aoc/aoc_u.h45
-rw-r--r--src/core/hle/service/aoc/purchase_event_manager.cpp67
-rw-r--r--src/core/hle/service/aoc/purchase_event_manager.h30
-rw-r--r--src/core/hle/service/services.cpp2
7 files changed, 372 insertions, 386 deletions
diff --git a/src/core/hle/service/aoc/addon_content_manager.cpp b/src/core/hle/service/aoc/addon_content_manager.cpp
new file mode 100644
index 000000000..d47f57d64
--- /dev/null
+++ b/src/core/hle/service/aoc/addon_content_manager.cpp
@@ -0,0 +1,223 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <numeric>
6#include <vector>
7
8#include "common/logging/log.h"
9#include "common/settings.h"
10#include "core/core.h"
11#include "core/file_sys/common_funcs.h"
12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/nca_metadata.h"
15#include "core/file_sys/patch_manager.h"
16#include "core/file_sys/registered_cache.h"
17#include "core/hle/kernel/k_event.h"
18#include "core/hle/service/aoc/addon_content_manager.h"
19#include "core/hle/service/aoc/purchase_event_manager.h"
20#include "core/hle/service/cmif_serialization.h"
21#include "core/hle/service/ipc_helpers.h"
22#include "core/hle/service/server_manager.h"
23#include "core/loader/loader.h"
24
25namespace Service::AOC {
26
27static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
28 return FileSys::GetBaseTitleID(title_id) == base;
29}
30
31static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
32 std::vector<u64> add_on_content;
33 const auto& rcu = system.GetContentProvider();
34 const auto list =
35 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
36 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
37 [](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
38 add_on_content.erase(
39 std::remove_if(
40 add_on_content.begin(), add_on_content.end(),
41 [&rcu](u64 tid) {
42 return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
43 Loader::ResultStatus::Success;
44 }),
45 add_on_content.end());
46 return add_on_content;
47}
48
49IAddOnContentManager::IAddOnContentManager(Core::System& system_)
50 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
51 service_context{system_, "aoc:u"} {
52 // clang-format off
53 static const FunctionInfo functions[] = {
54 {0, nullptr, "CountAddOnContentByApplicationId"},
55 {1, nullptr, "ListAddOnContentByApplicationId"},
56 {2, D<&IAddOnContentManager::CountAddOnContent>, "CountAddOnContent"},
57 {3, D<&IAddOnContentManager::ListAddOnContent>, "ListAddOnContent"},
58 {4, nullptr, "GetAddOnContentBaseIdByApplicationId"},
59 {5, D<&IAddOnContentManager::GetAddOnContentBaseId>, "GetAddOnContentBaseId"},
60 {6, nullptr, "PrepareAddOnContentByApplicationId"},
61 {7, D<&IAddOnContentManager::PrepareAddOnContent>, "PrepareAddOnContent"},
62 {8, D<&IAddOnContentManager::GetAddOnContentListChangedEvent>, "GetAddOnContentListChangedEvent"},
63 {9, nullptr, "GetAddOnContentLostErrorCode"},
64 {10, D<&IAddOnContentManager::GetAddOnContentListChangedEventWithProcessId>, "GetAddOnContentListChangedEventWithProcessId"},
65 {11, D<&IAddOnContentManager::NotifyMountAddOnContent>, "NotifyMountAddOnContent"},
66 {12, D<&IAddOnContentManager::NotifyUnmountAddOnContent>, "NotifyUnmountAddOnContent"},
67 {13, nullptr, "IsAddOnContentMountedForDebug"},
68 {50, D<&IAddOnContentManager::CheckAddOnContentMountStatus>, "CheckAddOnContentMountStatus"},
69 {100, D<&IAddOnContentManager::CreateEcPurchasedEventManager>, "CreateEcPurchasedEventManager"},
70 {101, D<&IAddOnContentManager::CreatePermanentEcPurchasedEventManager>, "CreatePermanentEcPurchasedEventManager"},
71 {110, nullptr, "CreateContentsServiceManager"},
72 {200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
73 {300, nullptr, "SetupHostAddOnContent"},
74 {301, nullptr, "GetRegisteredAddOnContentPath"},
75 {302, nullptr, "UpdateCachedList"},
76 };
77 // clang-format on
78
79 RegisterHandlers(functions);
80
81 aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
82}
83
84IAddOnContentManager::~IAddOnContentManager() {
85 service_context.CloseEvent(aoc_change_event);
86}
87
88Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
89 LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
90
91 const auto current = system.GetApplicationProcessProgramID();
92
93 const auto& disabled = Settings::values.disabled_addons[current];
94 if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
95 *out_count = 0;
96 R_SUCCEED();
97 }
98
99 *out_count = static_cast<u32>(
100 std::count_if(add_on_content.begin(), add_on_content.end(),
101 [current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }));
102
103 R_SUCCEED();
104}
105
106Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
107 OutBuffer<BufferAttr_HipcMapAlias> out_addons,
108 u32 offset, u32 count, ClientProcessId process_id) {
109 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
110 process_id.pid);
111
112 const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
113
114 std::vector<u32> out;
115 const auto& disabled = Settings::values.disabled_addons[current];
116 if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
117 for (u64 content_id : add_on_content) {
118 if (FileSys::GetBaseTitleID(content_id) != current) {
119 continue;
120 }
121
122 out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
123 }
124 }
125
126 // TODO(DarkLordZach): Find the correct error code.
127 R_UNLESS(out.size() >= offset, ResultUnknown);
128
129 *out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
130 std::rotate(out.begin(), out.begin() + offset, out.end());
131
132 std::memcpy(out_addons.data(), out.data(), *out_count * sizeof(u32));
133
134 R_SUCCEED();
135}
136
137Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
138 ClientProcessId process_id) {
139 LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
140
141 const auto title_id = system.GetApplicationProcessProgramID();
142 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
143 system.GetContentProvider()};
144
145 const auto res = pm.GetControlMetadata();
146 if (res.first == nullptr) {
147 *out_title_id = FileSys::GetAOCBaseTitleID(title_id);
148 R_SUCCEED();
149 }
150
151 *out_title_id = res.first->GetDLCBaseTitleId();
152
153 R_SUCCEED();
154}
155
156Result IAddOnContentManager::PrepareAddOnContent(s32 addon_index, ClientProcessId process_id) {
157 LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
158 process_id.pid);
159
160 R_SUCCEED();
161}
162
163Result IAddOnContentManager::GetAddOnContentListChangedEvent(
164 OutCopyHandle<Kernel::KReadableEvent> out_event) {
165 LOG_WARNING(Service_AOC, "(STUBBED) called");
166
167 *out_event = &aoc_change_event->GetReadableEvent();
168
169 R_SUCCEED();
170}
171
172Result IAddOnContentManager::GetAddOnContentListChangedEventWithProcessId(
173 OutCopyHandle<Kernel::KReadableEvent> out_event, ClientProcessId process_id) {
174 LOG_WARNING(Service_AOC, "(STUBBED) called");
175
176 *out_event = &aoc_change_event->GetReadableEvent();
177
178 R_SUCCEED();
179}
180
181Result IAddOnContentManager::NotifyMountAddOnContent() {
182 LOG_WARNING(Service_AOC, "(STUBBED) called");
183
184 R_SUCCEED();
185}
186
187Result IAddOnContentManager::NotifyUnmountAddOnContent() {
188 LOG_WARNING(Service_AOC, "(STUBBED) called");
189
190 R_SUCCEED();
191}
192
193Result IAddOnContentManager::CheckAddOnContentMountStatus() {
194 LOG_WARNING(Service_AOC, "(STUBBED) called");
195
196 R_SUCCEED();
197}
198
199Result IAddOnContentManager::CreateEcPurchasedEventManager(
200 OutInterface<IPurchaseEventManager> out_interface) {
201 LOG_WARNING(Service_AOC, "(STUBBED) called");
202
203 *out_interface = std::make_shared<IPurchaseEventManager>(system);
204
205 R_SUCCEED();
206}
207
208Result IAddOnContentManager::CreatePermanentEcPurchasedEventManager(
209 OutInterface<IPurchaseEventManager> out_interface) {
210 LOG_WARNING(Service_AOC, "(STUBBED) called");
211
212 *out_interface = std::make_shared<IPurchaseEventManager>(system);
213
214 R_SUCCEED();
215}
216
217void LoopProcess(Core::System& system) {
218 auto server_manager = std::make_unique<ServerManager>(system);
219 server_manager->RegisterNamedService("aoc:u", std::make_shared<IAddOnContentManager>(system));
220 ServerManager::RunServer(std::move(server_manager));
221}
222
223} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/addon_content_manager.h b/src/core/hle/service/aoc/addon_content_manager.h
new file mode 100644
index 000000000..91857df4c
--- /dev/null
+++ b/src/core/hle/service/aoc/addon_content_manager.h
@@ -0,0 +1,51 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Core {
11class System;
12}
13
14namespace Kernel {
15class KEvent;
16}
17
18namespace Service::AOC {
19
20class IPurchaseEventManager;
21
22class IAddOnContentManager final : public ServiceFramework<IAddOnContentManager> {
23public:
24 explicit IAddOnContentManager(Core::System& system);
25 ~IAddOnContentManager() override;
26
27 Result CountAddOnContent(Out<u32> out_count, ClientProcessId process_id);
28 Result ListAddOnContent(Out<u32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_addons,
29 u32 offset, u32 count, ClientProcessId process_id);
30 Result GetAddOnContentBaseId(Out<u64> out_title_id, ClientProcessId process_id);
31 Result PrepareAddOnContent(s32 addon_index, ClientProcessId process_id);
32 Result GetAddOnContentListChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
33 Result GetAddOnContentListChangedEventWithProcessId(
34 OutCopyHandle<Kernel::KReadableEvent> out_event, ClientProcessId process_id);
35 Result NotifyMountAddOnContent();
36 Result NotifyUnmountAddOnContent();
37 Result CheckAddOnContentMountStatus();
38 Result CreateEcPurchasedEventManager(OutInterface<IPurchaseEventManager> out_interface);
39 Result CreatePermanentEcPurchasedEventManager(
40 OutInterface<IPurchaseEventManager> out_interface);
41
42private:
43 std::vector<u64> add_on_content;
44 KernelHelpers::ServiceContext service_context;
45
46 Kernel::KEvent* aoc_change_event;
47};
48
49void LoopProcess(Core::System& system);
50
51} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
deleted file mode 100644
index 486719cc0..000000000
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <numeric>
6#include <vector>
7
8#include "common/logging/log.h"
9#include "common/settings.h"
10#include "core/core.h"
11#include "core/file_sys/common_funcs.h"
12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/nca_metadata.h"
15#include "core/file_sys/patch_manager.h"
16#include "core/file_sys/registered_cache.h"
17#include "core/hle/kernel/k_event.h"
18#include "core/hle/service/aoc/aoc_u.h"
19#include "core/hle/service/ipc_helpers.h"
20#include "core/hle/service/server_manager.h"
21#include "core/loader/loader.h"
22
23namespace Service::AOC {
24
25constexpr Result ResultNoPurchasedProductInfoAvailable{ErrorModule::NIMShop, 400};
26
27static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
28 return FileSys::GetBaseTitleID(title_id) == base;
29}
30
31static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
32 std::vector<u64> add_on_content;
33 const auto& rcu = system.GetContentProvider();
34 const auto list =
35 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
36 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
37 [](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
38 add_on_content.erase(
39 std::remove_if(
40 add_on_content.begin(), add_on_content.end(),
41 [&rcu](u64 tid) {
42 return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
43 Loader::ResultStatus::Success;
44 }),
45 add_on_content.end());
46 return add_on_content;
47}
48
49class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
50public:
51 explicit IPurchaseEventManager(Core::System& system_)
52 : ServiceFramework{system_, "IPurchaseEventManager"}, service_context{
53 system, "IPurchaseEventManager"} {
54 // clang-format off
55 static const FunctionInfo functions[] = {
56 {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
57 {1, &IPurchaseEventManager::SetDeliveryTarget, "SetDeliveryTarget"},
58 {2, &IPurchaseEventManager::GetPurchasedEventReadableHandle, "GetPurchasedEventReadableHandle"},
59 {3, &IPurchaseEventManager::PopPurchasedProductInfo, "PopPurchasedProductInfo"},
60 {4, &IPurchaseEventManager::PopPurchasedProductInfoWithUid, "PopPurchasedProductInfoWithUid"},
61 };
62 // clang-format on
63
64 RegisterHandlers(functions);
65
66 purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
67 }
68
69 ~IPurchaseEventManager() override {
70 service_context.CloseEvent(purchased_event);
71 }
72
73private:
74 void SetDefaultDeliveryTarget(HLERequestContext& ctx) {
75 IPC::RequestParser rp{ctx};
76
77 const auto unknown_1 = rp.Pop<u64>();
78 [[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
79
80 LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
81
82 IPC::ResponseBuilder rb{ctx, 2};
83 rb.Push(ResultSuccess);
84 }
85
86 void SetDeliveryTarget(HLERequestContext& ctx) {
87 IPC::RequestParser rp{ctx};
88
89 const auto unknown_1 = rp.Pop<u64>();
90 [[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
91
92 LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
93
94 IPC::ResponseBuilder rb{ctx, 2};
95 rb.Push(ResultSuccess);
96 }
97
98 void GetPurchasedEventReadableHandle(HLERequestContext& ctx) {
99 LOG_WARNING(Service_AOC, "called");
100
101 IPC::ResponseBuilder rb{ctx, 2, 1};
102 rb.Push(ResultSuccess);
103 rb.PushCopyObjects(purchased_event->GetReadableEvent());
104 }
105
106 void PopPurchasedProductInfo(HLERequestContext& ctx) {
107 LOG_DEBUG(Service_AOC, "(STUBBED) called");
108
109 IPC::ResponseBuilder rb{ctx, 2};
110 rb.Push(ResultNoPurchasedProductInfoAvailable);
111 }
112
113 void PopPurchasedProductInfoWithUid(HLERequestContext& ctx) {
114 LOG_DEBUG(Service_AOC, "(STUBBED) called");
115
116 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(ResultNoPurchasedProductInfoAvailable);
118 }
119
120 KernelHelpers::ServiceContext service_context;
121
122 Kernel::KEvent* purchased_event;
123};
124
125AOC_U::AOC_U(Core::System& system_)
126 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
127 service_context{system_, "aoc:u"} {
128 // clang-format off
129 static const FunctionInfo functions[] = {
130 {0, nullptr, "CountAddOnContentByApplicationId"},
131 {1, nullptr, "ListAddOnContentByApplicationId"},
132 {2, &AOC_U::CountAddOnContent, "CountAddOnContent"},
133 {3, &AOC_U::ListAddOnContent, "ListAddOnContent"},
134 {4, nullptr, "GetAddOnContentBaseIdByApplicationId"},
135 {5, &AOC_U::GetAddOnContentBaseId, "GetAddOnContentBaseId"},
136 {6, nullptr, "PrepareAddOnContentByApplicationId"},
137 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
138 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
139 {9, nullptr, "GetAddOnContentLostErrorCode"},
140 {10, &AOC_U::GetAddOnContentListChangedEventWithProcessId, "GetAddOnContentListChangedEventWithProcessId"},
141 {11, &AOC_U::NotifyMountAddOnContent, "NotifyMountAddOnContent"},
142 {12, &AOC_U::NotifyUnmountAddOnContent, "NotifyUnmountAddOnContent"},
143 {13, nullptr, "IsAddOnContentMountedForDebug"},
144 {50, &AOC_U::CheckAddOnContentMountStatus, "CheckAddOnContentMountStatus"},
145 {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
146 {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
147 {110, nullptr, "CreateContentsServiceManager"},
148 {200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
149 {300, nullptr, "SetupHostAddOnContent"},
150 {301, nullptr, "GetRegisteredAddOnContentPath"},
151 {302, nullptr, "UpdateCachedList"},
152 };
153 // clang-format on
154
155 RegisterHandlers(functions);
156
157 aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
158}
159
160AOC_U::~AOC_U() {
161 service_context.CloseEvent(aoc_change_event);
162}
163
164void AOC_U::CountAddOnContent(HLERequestContext& ctx) {
165 struct Parameters {
166 u64 process_id;
167 };
168 static_assert(sizeof(Parameters) == 8);
169
170 IPC::RequestParser rp{ctx};
171 const auto params = rp.PopRaw<Parameters>();
172
173 LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
174
175 IPC::ResponseBuilder rb{ctx, 3};
176 rb.Push(ResultSuccess);
177
178 const auto current = system.GetApplicationProcessProgramID();
179
180 const auto& disabled = Settings::values.disabled_addons[current];
181 if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
182 rb.Push<u32>(0);
183 return;
184 }
185
186 rb.Push<u32>(static_cast<u32>(
187 std::count_if(add_on_content.begin(), add_on_content.end(),
188 [current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); })));
189}
190
191void AOC_U::ListAddOnContent(HLERequestContext& ctx) {
192 struct Parameters {
193 u32 offset;
194 u32 count;
195 u64 process_id;
196 };
197 static_assert(sizeof(Parameters) == 16);
198
199 IPC::RequestParser rp{ctx};
200 const auto [offset, count, process_id] = rp.PopRaw<Parameters>();
201
202 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
203 process_id);
204
205 const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
206
207 std::vector<u32> out;
208 const auto& disabled = Settings::values.disabled_addons[current];
209 if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
210 for (u64 content_id : add_on_content) {
211 if (FileSys::GetBaseTitleID(content_id) != current) {
212 continue;
213 }
214
215 out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
216 }
217 }
218
219 if (out.size() < offset) {
220 IPC::ResponseBuilder rb{ctx, 2};
221 // TODO(DarkLordZach): Find the correct error code.
222 rb.Push(ResultUnknown);
223 return;
224 }
225
226 const auto out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
227 std::rotate(out.begin(), out.begin() + offset, out.end());
228 out.resize(out_count);
229
230 ctx.WriteBuffer(out);
231
232 IPC::ResponseBuilder rb{ctx, 3};
233 rb.Push(ResultSuccess);
234 rb.Push(out_count);
235}
236
237void AOC_U::GetAddOnContentBaseId(HLERequestContext& ctx) {
238 struct Parameters {
239 u64 process_id;
240 };
241 static_assert(sizeof(Parameters) == 8);
242
243 IPC::RequestParser rp{ctx};
244 const auto params = rp.PopRaw<Parameters>();
245
246 LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
247
248 IPC::ResponseBuilder rb{ctx, 4};
249 rb.Push(ResultSuccess);
250
251 const auto title_id = system.GetApplicationProcessProgramID();
252 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
253 system.GetContentProvider()};
254
255 const auto res = pm.GetControlMetadata();
256 if (res.first == nullptr) {
257 rb.Push(FileSys::GetAOCBaseTitleID(title_id));
258 return;
259 }
260
261 rb.Push(res.first->GetDLCBaseTitleId());
262}
263
264void AOC_U::PrepareAddOnContent(HLERequestContext& ctx) {
265 struct Parameters {
266 s32 addon_index;
267 u64 process_id;
268 };
269 static_assert(sizeof(Parameters) == 16);
270
271 IPC::RequestParser rp{ctx};
272 const auto [addon_index, process_id] = rp.PopRaw<Parameters>();
273
274 LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
275 process_id);
276
277 IPC::ResponseBuilder rb{ctx, 2};
278 rb.Push(ResultSuccess);
279}
280
281void AOC_U::GetAddOnContentListChangedEvent(HLERequestContext& ctx) {
282 LOG_WARNING(Service_AOC, "(STUBBED) called");
283
284 IPC::ResponseBuilder rb{ctx, 2, 1};
285 rb.Push(ResultSuccess);
286 rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
287}
288
289void AOC_U::GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx) {
290 LOG_WARNING(Service_AOC, "(STUBBED) called");
291
292 IPC::ResponseBuilder rb{ctx, 2, 1};
293 rb.Push(ResultSuccess);
294 rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
295}
296
297void AOC_U::NotifyMountAddOnContent(HLERequestContext& ctx) {
298 LOG_WARNING(Service_AOC, "(STUBBED) called");
299
300 IPC::ResponseBuilder rb{ctx, 2};
301 rb.Push(ResultSuccess);
302}
303
304void AOC_U::NotifyUnmountAddOnContent(HLERequestContext& ctx) {
305 LOG_WARNING(Service_AOC, "(STUBBED) called");
306
307 IPC::ResponseBuilder rb{ctx, 2};
308 rb.Push(ResultSuccess);
309}
310
311void AOC_U::CheckAddOnContentMountStatus(HLERequestContext& ctx) {
312 LOG_WARNING(Service_AOC, "(STUBBED) called");
313
314 IPC::ResponseBuilder rb{ctx, 2};
315 rb.Push(ResultSuccess);
316}
317
318void AOC_U::CreateEcPurchasedEventManager(HLERequestContext& ctx) {
319 LOG_WARNING(Service_AOC, "(STUBBED) called");
320
321 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
322 rb.Push(ResultSuccess);
323 rb.PushIpcInterface<IPurchaseEventManager>(system);
324}
325
326void AOC_U::CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx) {
327 LOG_WARNING(Service_AOC, "(STUBBED) called");
328
329 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
330 rb.Push(ResultSuccess);
331 rb.PushIpcInterface<IPurchaseEventManager>(system);
332}
333
334void LoopProcess(Core::System& system) {
335 auto server_manager = std::make_unique<ServerManager>(system);
336 server_manager->RegisterNamedService("aoc:u", std::make_shared<AOC_U>(system));
337 ServerManager::RunServer(std::move(server_manager));
338}
339
340} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
deleted file mode 100644
index 12ccfeb6a..000000000
--- a/src/core/hle/service/aoc/aoc_u.h
+++ /dev/null
@@ -1,45 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 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/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Kernel {
14class KEvent;
15}
16
17namespace Service::AOC {
18
19class AOC_U final : public ServiceFramework<AOC_U> {
20public:
21 explicit AOC_U(Core::System& system);
22 ~AOC_U() override;
23
24private:
25 void CountAddOnContent(HLERequestContext& ctx);
26 void ListAddOnContent(HLERequestContext& ctx);
27 void GetAddOnContentBaseId(HLERequestContext& ctx);
28 void PrepareAddOnContent(HLERequestContext& ctx);
29 void GetAddOnContentListChangedEvent(HLERequestContext& ctx);
30 void GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx);
31 void NotifyMountAddOnContent(HLERequestContext& ctx);
32 void NotifyUnmountAddOnContent(HLERequestContext& ctx);
33 void CheckAddOnContentMountStatus(HLERequestContext& ctx);
34 void CreateEcPurchasedEventManager(HLERequestContext& ctx);
35 void CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx);
36
37 std::vector<u64> add_on_content;
38 KernelHelpers::ServiceContext service_context;
39
40 Kernel::KEvent* aoc_change_event;
41};
42
43void LoopProcess(Core::System& system);
44
45} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/purchase_event_manager.cpp b/src/core/hle/service/aoc/purchase_event_manager.cpp
new file mode 100644
index 000000000..9e718510b
--- /dev/null
+++ b/src/core/hle/service/aoc/purchase_event_manager.cpp
@@ -0,0 +1,67 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/aoc/purchase_event_manager.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::AOC {
8
9constexpr Result ResultNoPurchasedProductInfoAvailable{ErrorModule::NIMShop, 400};
10
11IPurchaseEventManager::IPurchaseEventManager(Core::System& system_)
12 : ServiceFramework{system_, "IPurchaseEventManager"}, service_context{system,
13 "IPurchaseEventManager"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IPurchaseEventManager::SetDefaultDeliveryTarget>, "SetDefaultDeliveryTarget"},
17 {1, D<&IPurchaseEventManager::SetDeliveryTarget>, "SetDeliveryTarget"},
18 {2, D<&IPurchaseEventManager::GetPurchasedEvent>, "GetPurchasedEvent"},
19 {3, D<&IPurchaseEventManager::PopPurchasedProductInfo>, "PopPurchasedProductInfo"},
20 {4, D<&IPurchaseEventManager::PopPurchasedProductInfoWithUid>, "PopPurchasedProductInfoWithUid"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25
26 purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
27}
28
29IPurchaseEventManager::~IPurchaseEventManager() {
30 service_context.CloseEvent(purchased_event);
31}
32
33Result IPurchaseEventManager::SetDefaultDeliveryTarget(
34 ClientProcessId process_id, InBuffer<BufferAttr_HipcMapAlias> in_buffer) {
35 LOG_WARNING(Service_AOC, "(STUBBED) called, process_id={}", process_id.pid);
36
37 R_SUCCEED();
38}
39
40Result IPurchaseEventManager::SetDeliveryTarget(u64 unknown,
41 InBuffer<BufferAttr_HipcMapAlias> in_buffer) {
42 LOG_WARNING(Service_AOC, "(STUBBED) called, unknown={}", unknown);
43
44 R_SUCCEED();
45}
46
47Result IPurchaseEventManager::GetPurchasedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
48 LOG_WARNING(Service_AOC, "called");
49
50 *out_event = &purchased_event->GetReadableEvent();
51
52 R_SUCCEED();
53}
54
55Result IPurchaseEventManager::PopPurchasedProductInfo() {
56 LOG_DEBUG(Service_AOC, "(STUBBED) called");
57
58 R_RETURN(ResultNoPurchasedProductInfoAvailable);
59}
60
61Result IPurchaseEventManager::PopPurchasedProductInfoWithUid() {
62 LOG_DEBUG(Service_AOC, "(STUBBED) called");
63
64 R_RETURN(ResultNoPurchasedProductInfoAvailable);
65}
66
67} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/purchase_event_manager.h b/src/core/hle/service/aoc/purchase_event_manager.h
new file mode 100644
index 000000000..ea3836bc9
--- /dev/null
+++ b/src/core/hle/service/aoc/purchase_event_manager.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/os/event.h"
9#include "core/hle/service/service.h"
10
11namespace Service::AOC {
12
13class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
14public:
15 explicit IPurchaseEventManager(Core::System& system_);
16 ~IPurchaseEventManager() override;
17
18 Result SetDefaultDeliveryTarget(ClientProcessId process_id,
19 InBuffer<BufferAttr_HipcMapAlias> in_buffer);
20 Result SetDeliveryTarget(u64 unknown, InBuffer<BufferAttr_HipcMapAlias> in_buffer);
21 Result GetPurchasedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
22 Result PopPurchasedProductInfo();
23 Result PopPurchasedProductInfoWithUid();
24
25private:
26 KernelHelpers::ServiceContext service_context;
27 Kernel::KEvent* purchased_event;
28};
29
30} // namespace Service::AOC
diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp
index 1aa85ea54..3defa4b31 100644
--- a/src/core/hle/service/services.cpp
+++ b/src/core/hle/service/services.cpp
@@ -5,7 +5,7 @@
5 5
6#include "core/hle/service/acc/acc.h" 6#include "core/hle/service/acc/acc.h"
7#include "core/hle/service/am/am.h" 7#include "core/hle/service/am/am.h"
8#include "core/hle/service/aoc/aoc_u.h" 8#include "core/hle/service/aoc/addon_content_manager.h"
9#include "core/hle/service/apm/apm.h" 9#include "core/hle/service/apm/apm.h"
10#include "core/hle/service/audio/audio.h" 10#include "core/hle/service/audio/audio.h"
11#include "core/hle/service/bcat/bcat.h" 11#include "core/hle/service/bcat/bcat.h"