summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/kernel/errors.h74
-rw-r--r--src/core/hle/kernel/svc.cpp66
-rw-r--r--src/core/hle/kernel/svc_wrap.h5
-rw-r--r--src/core/hle/kernel/thread.cpp48
-rw-r--r--src/core/hle/kernel/thread.h2
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/am/am.cpp27
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp38
-rw-r--r--src/core/hle/service/btm/btm.cpp108
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp44
-rw-r--r--src/core/hle/service/filesystem/filesystem.h3
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp58
-rw-r--r--src/core/hle/service/hid/hid.cpp16
-rw-r--r--src/core/hle/service/spl/module.cpp3
-rw-r--r--src/core/hle/service/time/interface.cpp3
-rw-r--r--src/core/hle/service/time/time.cpp15
-rw-r--r--src/core/hle/service/time/time.h1
-rw-r--r--src/core/hle/service/vi/vi.cpp22
22 files changed, 407 insertions, 153 deletions
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index ee698c8a7..8b58d701d 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -8,58 +8,28 @@
namespace Kernel {
-namespace ErrCodes {
-enum {
- // Confirmed Switch OS error codes
- MaxConnectionsReached = 7,
- InvalidSize = 101,
- InvalidAddress = 102,
- HandleTableFull = 105,
- InvalidMemoryState = 106,
- InvalidMemoryPermissions = 108,
- InvalidMemoryRange = 110,
- InvalidThreadPriority = 112,
- InvalidProcessorId = 113,
- InvalidHandle = 114,
- InvalidPointer = 115,
- InvalidCombination = 116,
- Timeout = 117,
- SynchronizationCanceled = 118,
- TooLarge = 119,
- InvalidEnumValue = 120,
- NoSuchEntry = 121,
- AlreadyRegistered = 122,
- SessionClosed = 123,
- InvalidState = 125,
- ResourceLimitExceeded = 132,
-};
-}
+// Confirmed Switch kernel error codes
-// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always
-// double check that the code matches before re-using the constant.
-
-constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull);
-constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrorModule::Kernel, ErrCodes::SessionClosed);
-constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge);
-constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrorModule::Kernel,
- ErrCodes::MaxConnectionsReached);
-constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue);
-constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorModule::Kernel,
- ErrCodes::InvalidCombination);
-constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
-constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
-constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
- ErrCodes::InvalidMemoryPermissions);
-constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange);
-constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
-constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
-constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
-constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered);
-constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
-constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
- ErrCodes::InvalidThreadPriority);
-constexpr ResultCode ERR_INVALID_POINTER(ErrorModule::Kernel, ErrCodes::InvalidPointer);
-constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry);
-constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
+constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
+constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
+constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
+constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
+constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
+constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
+constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
+constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
+constexpr ResultCode ERR_INVALID_THREAD_PRIORITY{ErrorModule::Kernel, 112};
+constexpr ResultCode ERR_INVALID_HANDLE{ErrorModule::Kernel, 114};
+constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
+constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
+constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
+constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
+constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
+constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
+constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
+constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122};
+constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123};
+constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125};
+constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132};
} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index b0b6508d9..75dbfc31d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -123,6 +123,48 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
return RESULT_SUCCESS;
}
+static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
+ LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot);
+
+ if (!Common::Is4KBAligned(addr)) {
+ return ERR_INVALID_ADDRESS;
+ }
+
+ if (size == 0 || !Common::Is4KBAligned(size)) {
+ return ERR_INVALID_SIZE;
+ }
+
+ if (!IsValidAddressRange(addr, size)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ const auto permission = static_cast<MemoryPermission>(prot);
+ if (permission != MemoryPermission::None && permission != MemoryPermission::Read &&
+ permission != MemoryPermission::ReadWrite) {
+ return ERR_INVALID_MEMORY_PERMISSIONS;
+ }
+
+ auto* const current_process = Core::CurrentProcess();
+ auto& vm_manager = current_process->VMManager();
+
+ if (!IsInsideAddressSpace(vm_manager, addr, size)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ const VMManager::VMAHandle iter = vm_manager.FindVMA(addr);
+ if (iter == vm_manager.vma_map.end()) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ LOG_WARNING(Kernel_SVC, "Uniformity check on protected memory is not implemented.");
+ // TODO: Performs a uniformity check to make sure only protected memory is changed (it doesn't
+ // make sense to allow changing permissions on kernel memory itself, etc).
+
+ const auto converted_permissions = SharedMemory::ConvertPermissions(permission);
+
+ return vm_manager.ReprotectRange(addr, size, converted_permissions);
+}
+
static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
LOG_WARNING(Kernel_SVC,
"(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr,
@@ -172,7 +214,7 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
// Read 1 char beyond the max allowed port name to detect names that are too long.
std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
if (port_name.size() > PortNameMaxLength) {
- return ERR_PORT_NAME_TOO_LONG;
+ return ERR_OUT_OF_RANGE;
}
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
@@ -268,8 +310,9 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
static constexpr u64 MaxHandles = 0x40;
- if (handle_count > MaxHandles)
- return ResultCode(ErrorModule::Kernel, ErrCodes::TooLarge);
+ if (handle_count > MaxHandles) {
+ return ERR_OUT_OF_RANGE;
+ }
auto* const thread = GetCurrentThread();
@@ -334,8 +377,7 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
}
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
- thread->SetWaitSynchronizationResult(
- ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled));
+ thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
thread->ResumeFromWait();
return RESULT_SUCCESS;
}
@@ -564,7 +606,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
}
if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
- return ERR_INVALID_COMBINATION_KERNEL;
+ return ERR_INVALID_COMBINATION;
}
*result = current_process->GetRandomEntropy(info_sub_id);
@@ -601,7 +643,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
case GetInfoType::ThreadTickCount: {
constexpr u64 num_cpus = 4;
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
- return ERR_INVALID_COMBINATION_KERNEL;
+ return ERR_INVALID_COMBINATION;
}
const auto thread =
@@ -1139,7 +1181,7 @@ static ResultCode CloseHandle(Handle handle) {
/// Reset an event
static ResultCode ResetSignal(Handle handle) {
- LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
+ LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
auto event = handle_table.Get<Event>(handle);
@@ -1194,7 +1236,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
}
if (mask == 0) {
- return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
+ return ERR_INVALID_COMBINATION;
}
/// This value is used to only change the affinity mask without changing the current ideal core.
@@ -1203,12 +1245,12 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
if (core == OnlyChangeMask) {
core = thread->GetIdealCore();
} else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
- return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
+ return ERR_INVALID_PROCESSOR_ID;
}
// Error out if the input core isn't enabled in the input mask.
if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
- return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
+ return ERR_INVALID_COMBINATION;
}
thread->ChangeCore(core, mask);
@@ -1297,7 +1339,7 @@ struct FunctionDef {
static const FunctionDef SVC_Table[] = {
{0x00, nullptr, "Unknown"},
{0x01, SvcWrap<SetHeapSize>, "SetHeapSize"},
- {0x02, nullptr, "SetMemoryPermission"},
+ {0x02, SvcWrap<SetMemoryPermission>, "SetMemoryPermission"},
{0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"},
{0x04, SvcWrap<MapMemory>, "MapMemory"},
{0x05, SvcWrap<UnmapMemory>, "UnmapMemory"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index b09753c80..233a99fb0 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -121,6 +121,11 @@ void SvcWrap() {
FuncReturn(func(Param(0), Param(1), Param(2)).raw);
}
+template <ResultCode func(u64, u64, u32)>
+void SvcWrap() {
+ FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
+}
+
template <ResultCode func(u32, u64, u64, u32)>
void SvcWrap() {
FuncReturn(
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index dd5cd9ced..4ffb76818 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -142,36 +142,7 @@ void Thread::ResumeFromWait() {
status = ThreadStatus::Ready;
- std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask);
- if (!new_processor_id) {
- new_processor_id = processor_id;
- }
- if (ideal_core != -1 &&
- Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
- new_processor_id = ideal_core;
- }
-
- ASSERT(*new_processor_id < 4);
-
- // Add thread to new core's scheduler
- auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id);
-
- if (*new_processor_id != processor_id) {
- // Remove thread from previous core's scheduler
- scheduler->RemoveThread(this);
- next_scheduler->AddThread(this, current_priority);
- }
-
- processor_id = *new_processor_id;
-
- // If the thread was ready, unschedule from the previous core and schedule on the new core
- scheduler->UnscheduleThread(this, current_priority);
- next_scheduler->ScheduleThread(this, current_priority);
-
- // Change thread's scheduler
- scheduler = next_scheduler;
-
- Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
+ ChangeScheduler();
}
/**
@@ -364,42 +335,45 @@ void Thread::UpdatePriority() {
void Thread::ChangeCore(u32 core, u64 mask) {
ideal_core = core;
affinity_mask = mask;
+ ChangeScheduler();
+}
+void Thread::ChangeScheduler() {
if (status != ThreadStatus::Ready) {
return;
}
+ auto& system = Core::System::GetInstance();
std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
if (!new_processor_id) {
new_processor_id = processor_id;
}
- if (ideal_core != -1 &&
- Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
+ if (ideal_core != -1 && system.Scheduler(ideal_core).GetCurrentThread() == nullptr) {
new_processor_id = ideal_core;
}
ASSERT(*new_processor_id < 4);
// Add thread to new core's scheduler
- auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id);
+ auto& next_scheduler = system.Scheduler(*new_processor_id);
if (*new_processor_id != processor_id) {
// Remove thread from previous core's scheduler
scheduler->RemoveThread(this);
- next_scheduler->AddThread(this, current_priority);
+ next_scheduler.AddThread(this, current_priority);
}
processor_id = *new_processor_id;
// If the thread was ready, unschedule from the previous core and schedule on the new core
scheduler->UnscheduleThread(this, current_priority);
- next_scheduler->ScheduleThread(this, current_priority);
+ next_scheduler.ScheduleThread(this, current_priority);
// Change thread's scheduler
- scheduler = next_scheduler;
+ scheduler = &next_scheduler;
- Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
+ system.CpuCore(processor_id).PrepareReschedule();
}
bool Thread::AllWaitObjectsReady() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 4a6e11239..d384d50db 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -374,6 +374,8 @@ private:
explicit Thread(KernelCore& kernel);
~Thread() override;
+ void ChangeScheduler();
+
Core::ARM_Interface::ThreadContext context{};
u32 thread_id = 0;
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index c6b18cfba..bfb77cc31 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -19,8 +19,6 @@
enum class ErrorDescription : u32 {
Success = 0,
RemoteProcessDead = 301,
- InvalidOffset = 6061,
- InvalidLength = 6062,
};
/**
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 0477ce66e..3758ecae1 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -203,8 +203,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
ISelfController::~ISelfController() = default;
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
- // Takes 3 input u8s with each field located immediately after the previous u8, these are
- // bool flags. No output.
+ // Takes 3 input u8s with each field located immediately after the previous
+ // u8, these are bool flags. No output.
IPC::RequestParser rp{ctx};
@@ -258,8 +258,8 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont
}
void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
- // Takes 3 input u8s with each field located immediately after the previous u8, these are
- // bool flags. No output.
+ // Takes 3 input u8s with each field located immediately after the previous
+ // u8, these are bool flags. No output.
IPC::RequestParser rp{ctx};
bool enabled = rp.Pop<bool>();
@@ -302,8 +302,8 @@ void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& c
}
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
- // TODO(Subv): Find out how AM determines the display to use, for now just create the layer
- // in the Default display.
+ // TODO(Subv): Find out how AM determines the display to use, for now just
+ // create the layer in the Default display.
u64 display_id = nvflinger->OpenDisplay("Default");
u64 layer_id = nvflinger->CreateLayer(display_id);
@@ -733,7 +733,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{70, nullptr, "RequestToShutdown"},
{71, nullptr, "RequestToReboot"},
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
- {90, nullptr, "EnableApplicationCrashReport"},
+ {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
{100, nullptr, "InitializeApplicationCopyrightFrameBuffer"},
{101, nullptr, "SetApplicationCopyrightImage"},
{102, nullptr, "SetApplicationCopyrightVisibility"},
@@ -752,6 +752,12 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
IApplicationFunctions::~IApplicationFunctions() = default;
+void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -821,7 +827,8 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
- // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak.
+ // For example, in some cases official apps use this with error 0x2A2 then
+ // uses svcBreak.
IPC::RequestParser rp{ctx};
u32 result = rp.Pop<u32>();
@@ -884,8 +891,8 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
auto message_queue = std::make_shared<AppletMessageQueue>();
- message_queue->PushMessage(
- AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot
+ message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
+ // game boot
std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 2f1c20bce..5a3fcba8f 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -185,6 +185,7 @@ private:
void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
void EndBlockingHomeButton(Kernel::HLERequestContext& ctx);
+ void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 35a8bef6c..d3ea57ea7 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -28,13 +28,13 @@ public:
{1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
{2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
{3, &IAudioRenderer::GetState, "GetState"},
- {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
+ {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"},
{5, &IAudioRenderer::Start, "Start"},
{6, &IAudioRenderer::Stop, "Stop"},
{7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
{8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
{9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
- {10, nullptr, "RequestUpdateAuto"},
+ {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"},
{11, nullptr, "ExecuteAudioRendererRendering"},
};
// clang-format on
@@ -79,7 +79,7 @@ private:
LOG_DEBUG(Service_Audio, "called");
}
- void RequestUpdate(Kernel::HLERequestContext& ctx) {
+ void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 783c39503..763e619a4 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -77,8 +77,8 @@ private:
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(consumed);
- rb.Push<u64>(performance);
rb.Push<u32>(sample_count);
+ rb.Push<u64>(performance);
ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
}
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index d0a15cc4c..f3bde6d0d 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -2,12 +2,49 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/btdrv/btdrv.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::BtDrv {
+class Bt final : public ServiceFramework<Bt> {
+public:
+ explicit Bt() : ServiceFramework{"bt"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
+ {9, &Bt::RegisterEvent, "RegisterEvent"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+ }
+
+private:
+ void RegisterEvent(Kernel::HLERequestContext& ctx) {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ register_event =
+ Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent");
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(register_event);
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ }
+ Kernel::SharedPtr<Kernel::Event> register_event;
+};
+
class BtDrv final : public ServiceFramework<BtDrv> {
public:
explicit BtDrv() : ServiceFramework{"btdrv"} {
@@ -67,6 +104,7 @@ public:
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<BtDrv>()->InstallAsService(sm);
+ std::make_shared<Bt>()->InstallAsService(sm);
}
} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index b949bfabd..a02f6b53a 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -6,13 +6,118 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/btm/btm.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::BTM {
+class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
+public:
+ explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IBtmUserCore::GetScanEvent, "GetScanEvent"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
+ {9, nullptr, "Unknown9"},
+ {10, nullptr, "Unknown10"},
+ {17, &IBtmUserCore::GetConnectionEvent, "GetConnectionEvent"},
+ {18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "Unknown20"},
+ {21, nullptr, "Unknown21"},
+ {22, nullptr, "Unknown22"},
+ {23, nullptr, "Unknown23"},
+ {24, nullptr, "Unknown24"},
+ {25, nullptr, "Unknown25"},
+ {26, &IBtmUserCore::GetDiscoveryEvent, "AcquireBleServiceDiscoveryEventImpl"},
+ {27, nullptr, "Unknown27"},
+ {28, nullptr, "Unknown28"},
+ {29, nullptr, "Unknown29"},
+ {30, nullptr, "Unknown30"},
+ {31, nullptr, "Unknown31"},
+ {32, nullptr, "Unknown32"},
+ {33, &IBtmUserCore::GetConfigEvent, "GetConfigEvent"},
+ {34, nullptr, "Unknown34"},
+ {35, nullptr, "Unknown35"},
+ {36, nullptr, "Unknown36"},
+ {37, nullptr, "Unknown37"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetScanEvent(Kernel::HLERequestContext& ctx) {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ scan_event =
+ Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent");
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(scan_event);
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ }
+ void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
+ "IBtmUserCore:ConnectionEvent");
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(connection_event);
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ }
+ void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ service_discovery =
+ Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(service_discovery);
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ }
+ void GetConfigEvent(Kernel::HLERequestContext& ctx) {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ config_event =
+ Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent");
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(config_event);
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ }
+ Kernel::SharedPtr<Kernel::Event> scan_event;
+ Kernel::SharedPtr<Kernel::Event> connection_event;
+ Kernel::SharedPtr<Kernel::Event> service_discovery;
+ Kernel::SharedPtr<Kernel::Event> config_event;
+};
+
+class BTM_USR final : public ServiceFramework<BTM_USR> {
+public:
+ explicit BTM_USR() : ServiceFramework{"btm:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &BTM_USR::GetCoreImpl, "GetCoreImpl"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetCoreImpl(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IBtmUserCore>();
+ LOG_DEBUG(Service_BTM, "called");
+ }
+};
+
class BTM final : public ServiceFramework<BTM> {
public:
explicit BTM() : ServiceFramework{"btm"} {
@@ -116,6 +221,7 @@ void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<BTM>()->InstallAsService(sm);
std::make_shared<BTM_DBG>()->InstallAsService(sm);
std::make_shared<BTM_SYS>()->InstallAsService(sm);
+ std::make_shared<BTM_USR>()->InstallAsService(sm);
}
} // namespace Service::BTM
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index ea8fd965a..5d6294016 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -303,7 +303,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
static_cast<u8>(space), save_struct.DebugInfo());
if (save_data_factory == nullptr) {
- return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Open(space, save_struct);
@@ -313,7 +313,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
if (save_data_factory == nullptr) {
- return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
@@ -323,15 +323,22 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
- return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound);
+ return FileSys::ERROR_SD_CARD_NOT_FOUND;
}
return sdmc_factory->Open();
}
-std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
- return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
- GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
+std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union;
+
+std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
+ if (registered_cache_union == nullptr) {
+ registered_cache_union =
+ std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
+ GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
+ }
+
+ return registered_cache_union;
}
FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -370,6 +377,15 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
return bis_factory->GetModificationLoadRoot(title_id);
}
+FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
+ LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetModificationDumpRoot(title_id);
+}
+
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (overwrite) {
bis_factory = nullptr;
@@ -383,13 +399,21 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
FileSys::Mode::ReadWrite);
auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
FileSys::Mode::ReadWrite);
+ auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
+ FileSys::Mode::ReadWrite);
- if (bis_factory == nullptr)
- bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory);
- if (save_data_factory == nullptr)
+ if (bis_factory == nullptr) {
+ bis_factory =
+ std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory);
+ }
+
+ if (save_data_factory == nullptr) {
save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
- if (sdmc_factory == nullptr)
+ }
+
+ if (sdmc_factory == nullptr) {
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
+ }
}
void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 2cbb70c87..ff9182e84 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -48,13 +48,14 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
-std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
+std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
FileSys::RegisteredCache* GetSystemNANDContents();
FileSys::RegisteredCache* GetUserNANDContents();
FileSys::RegisteredCache* GetSDMCContents();
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
+FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
// above is called.
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index b9a1d5105..038dc80b1 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -63,12 +63,12 @@ private:
// Error checking
if (length < 0) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ rb.Push(FileSys::ERROR_INVALID_SIZE);
return;
}
if (offset < 0) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ rb.Push(FileSys::ERROR_INVALID_OFFSET);
return;
}
@@ -108,12 +108,12 @@ private:
// Error checking
if (length < 0) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ rb.Push(FileSys::ERROR_INVALID_SIZE);
return;
}
if (offset < 0) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ rb.Push(FileSys::ERROR_INVALID_OFFSET);
return;
}
@@ -139,12 +139,12 @@ private:
// Error checking
if (length < 0) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ rb.Push(FileSys::ERROR_INVALID_SIZE);
return;
}
if (offset < 0) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ rb.Push(FileSys::ERROR_INVALID_OFFSET);
return;
}
@@ -744,7 +744,7 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound));
+ rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
}
@@ -836,7 +836,7 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
static_cast<u8>(storage_id), title_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound));
+ rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 56c415e4e..205e4fd14 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -40,6 +40,29 @@ enum class JoystickId : std::size_t {
Joystick_Right,
};
+static std::size_t NPadIdToIndex(u32 npad_id) {
+ switch (npad_id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return npad_id;
+ case 8:
+ case NPAD_HANDHELD:
+ return 8;
+ case 9:
+ case NPAD_UNKNOWN:
+ return 9;
+ default:
+ UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
+ return 0;
+ }
+}
+
Controller_NPad::Controller_NPad() = default;
Controller_NPad::~Controller_NPad() = default;
@@ -288,10 +311,11 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
switch (controller_type) {
case NPadControllerType::Handheld:
handheld_entry.connection_status.raw = 0;
- handheld_entry.connection_status.IsConnected.Assign(1);
- if (!Settings::values.use_docked_mode) {
- handheld_entry.connection_status.IsWired.Assign(1);
- }
+ handheld_entry.connection_status.IsWired.Assign(1);
+ handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
+ handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
+ handheld_entry.connection_status.IsRightJoyWired.Assign(1);
handheld_entry.pad_states.raw = pad_state.raw;
handheld_entry.l_stick = lstick_entry;
handheld_entry.r_stick = rstick_entry;
@@ -371,16 +395,30 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
supported_npad_id_types.clear();
supported_npad_id_types.resize(length / sizeof(u32));
std::memcpy(supported_npad_id_types.data(), data, length);
+ bool had_controller_update = false;
for (std::size_t i = 0; i < connected_controllers.size(); i++) {
auto& controller = connected_controllers[i];
if (!controller.is_connected) {
continue;
}
if (!IsControllerSupported(PREFERRED_CONTROLLER)) {
- controller.type = DecideBestController(PREFERRED_CONTROLLER);
- InitNewlyAddedControler(i);
+ const auto best_type = DecideBestController(PREFERRED_CONTROLLER);
+ const bool is_handheld = (best_type == NPadControllerType::Handheld ||
+ PREFERRED_CONTROLLER == NPadControllerType::Handheld);
+ if (is_handheld) {
+ controller.type = NPadControllerType::None;
+ controller.is_connected = false;
+ AddNewController(best_type);
+ } else {
+ controller.type = best_type;
+ InitNewlyAddedControler(i);
+ }
+ had_controller_update = true;
}
}
+ if (had_controller_update) {
+ styleset_changed_event->Signal();
+ }
}
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -458,15 +496,11 @@ void Controller_NPad::AddNewController(NPadControllerType controller) {
}
void Controller_NPad::ConnectNPad(u32 npad_id) {
- if (npad_id >= connected_controllers.size())
- return;
- connected_controllers[npad_id].is_connected = true;
+ connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
}
void Controller_NPad::DisconnectNPad(u32 npad_id) {
- if (npad_id >= connected_controllers.size())
- return;
- connected_controllers[npad_id].is_connected = false;
+ connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
}
Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a45fd4954..39631b14f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -286,10 +286,10 @@ public:
{519, nullptr, "GetPalmaOperationResult"},
{520, nullptr, "ReadPalmaPlayLog"},
{521, nullptr, "ResetPalmaPlayLog"},
- {522, nullptr, "SetIsPalmaAllConnectable"},
+ {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
{523, nullptr, "SetIsPalmaPairedConnectable"},
{524, nullptr, "PairPalma"},
- {525, nullptr, "SetPalmaBoostMode"},
+ {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
{1000, nullptr, "SetNpadCommunicationMode"},
{1001, nullptr, "GetNpadCommunicationMode"},
};
@@ -596,6 +596,18 @@ private:
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+
+ void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
+ void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
};
class HidDbg final : public ServiceFramework<HidDbg> {
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 69c260408..b2de2a818 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -28,8 +28,9 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
std::size_t size = ctx.GetWriteBufferSize();
+ std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max());
std::vector<u8> data(size);
- std::generate(data.begin(), data.end(), rng);
+ std::generate(data.begin(), data.end(), [&] { return static_cast<u8>(distribution(rng)); });
ctx.WriteBuffer(data);
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index e3cbd7004..b3a196f65 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -23,7 +23,8 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
{400, &Time::GetClockSnapshot, "GetClockSnapshot"},
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
- {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
+ {500, &Time::CalculateStandardUserSystemClockDifferenceByUser,
+ "CalculateStandardUserSystemClockDifferenceByUser"},
{501, nullptr, "CalculateSpanBetween"},
};
RegisterHandlers(functions);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 85e7b1195..e561a0c52 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -299,6 +299,21 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
}
+void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
+ Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ IPC::RequestParser rp{ctx};
+ const auto snapshot_a = rp.PopRaw<ClockSnapshot>();
+ const auto snapshot_b = rp.PopRaw<ClockSnapshot>();
+ const u64 difference =
+ snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset;
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u64>(difference);
+}
+
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
: ServiceFramework(name), time(std::move(time)) {}
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 77871ae07..ea43fbea7 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -84,6 +84,7 @@ public:
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
void GetClockSnapshot(Kernel::HLERequestContext& ctx);
+ void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> time;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d764b2406..d25fdb1fe 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -237,6 +237,22 @@ private:
Data data{};
};
+/// Represents a parcel containing one int '0' as its data
+/// Used by DetachBuffer and Disconnect
+class IGBPEmptyResponseParcel : public Parcel {
+protected:
+ void SerializeData() override {
+ Write(data);
+ }
+
+private:
+ struct Data {
+ u32_le unk_0;
+ };
+
+ Data data{};
+};
+
class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
public:
explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer)
@@ -554,6 +570,12 @@ private:
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::CancelBuffer) {
LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
+ } else if (transaction == TransactionId::Disconnect ||
+ transaction == TransactionId::DetachBuffer) {
+ const auto buffer = ctx.ReadBuffer();
+
+ IGBPEmptyResponseParcel response{};
+ ctx.WriteBuffer(response.Serialize());
} else {
ASSERT_MSG(false, "Unimplemented");
}