summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/kernel/process.cpp6
-rw-r--r--src/core/hle/kernel/process.h1
-rw-r--r--src/core/hle/result.h58
-rw-r--r--src/core/hle/service/ac_u.cpp19
-rw-r--r--src/core/hle/service/cam/cam.cpp282
-rw-r--r--src/core/hle/service/cam/cam.h262
-rw-r--r--src/core/hle/service/cam/cam_u.cpp39
-rw-r--r--src/core/hle/service/dsp_dsp.cpp223
-rw-r--r--src/core/loader/ncch.cpp3
-rw-r--r--src/core/memory.cpp2
10 files changed, 776 insertions, 119 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 16eb972fb..24b266eae 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -130,9 +130,11 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
}
+VAddr Process::GetLinearHeapAreaAddress() const {
+ return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR;
+}
VAddr Process::GetLinearHeapBase() const {
- return (kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR)
- + memory_region->base;
+ return GetLinearHeapAreaAddress() + memory_region->base;
}
VAddr Process::GetLinearHeapLimit() const {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 60e17f251..6d2ca96a2 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -143,6 +143,7 @@ public:
/// Bitmask of the used TLS slots
std::bitset<300> used_tls_slots;
+ VAddr GetLinearHeapAreaAddress() const;
VAddr GetLinearHeapBase() const;
VAddr GetLinearHeapLimit() const;
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 0fce5988b..69613fbbb 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -269,7 +269,6 @@ public:
: result_code(error_code)
{
ASSERT(error_code.IsError());
- UpdateDebugPtr();
}
/**
@@ -287,40 +286,37 @@ public:
: result_code(o.result_code)
{
if (!o.empty()) {
- new (&storage) T(*o.GetPointer());
+ new (&object) T(o.object);
}
- UpdateDebugPtr();
}
ResultVal(ResultVal&& o)
: result_code(o.result_code)
{
if (!o.empty()) {
- new (&storage) T(std::move(*o.GetPointer()));
+ new (&object) T(std::move(o.object));
}
- UpdateDebugPtr();
}
~ResultVal() {
if (!empty()) {
- GetPointer()->~T();
+ object.~T();
}
}
ResultVal& operator=(const ResultVal& o) {
if (!empty()) {
if (!o.empty()) {
- *GetPointer() = *o.GetPointer();
+ object = o.object;
} else {
- GetPointer()->~T();
+ object.~T();
}
} else {
if (!o.empty()) {
- new (&storage) T(*o.GetPointer());
+ new (&object) T(o.object);
}
}
result_code = o.result_code;
- UpdateDebugPtr();
return *this;
}
@@ -333,11 +329,10 @@ public:
void emplace(ResultCode success_code, Args&&... args) {
ASSERT(success_code.IsSuccess());
if (!empty()) {
- GetPointer()->~T();
+ object.~T();
}
- new (&storage) T(std::forward<Args>(args)...);
+ new (&object) T(std::forward<Args>(args)...);
result_code = success_code;
- UpdateDebugPtr();
}
/// Returns true if the `ResultVal` contains an error code and no value.
@@ -350,15 +345,15 @@ public:
ResultCode Code() const { return result_code; }
- const T& operator* () const { return *GetPointer(); }
- T& operator* () { return *GetPointer(); }
- const T* operator->() const { return GetPointer(); }
- T* operator->() { return GetPointer(); }
+ const T& operator* () const { return object; }
+ T& operator* () { return object; }
+ const T* operator->() const { return &object; }
+ T* operator->() { return &object; }
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
template <typename U>
T ValueOr(U&& value) const {
- return !empty() ? *GetPointer() : std::move(value);
+ return !empty() ? object : std::move(value);
}
/// Asserts that the result succeeded and returns a reference to it.
@@ -372,31 +367,10 @@ public:
}
private:
- typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType;
-
- StorageType storage;
+ // A union is used to allocate the storage for the value, while allowing us to construct and
+ // destruct it at will.
+ union { T object; };
ResultCode result_code;
-#ifdef _DEBUG
- // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the
- // need to cast `storage` to a pointer or pay attention to `result_code`.
- const T* debug_ptr;
-#endif
-
- void UpdateDebugPtr() {
-#ifdef _DEBUG
- debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage));
-#endif
- }
-
- const T* GetPointer() const {
- ASSERT(!empty());
- return static_cast<const T*>(static_cast<const void*>(&storage));
- }
-
- T* GetPointer() {
- ASSERT(!empty());
- return static_cast<T*>(static_cast<void*>(&storage));
- }
};
/**
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index c48259e13..d67325506 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -22,12 +22,27 @@ static void GetWifiStatus(Service::Interface* self) {
// TODO(purpasmart96): This function is only a stub,
// it returns a valid result without implementing full functionality.
- cmd_buff[1] = 0; // No error
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0; // Connection type set to none
LOG_WARNING(Service_AC, "(STUBBED) called");
}
+/**
+ * AC_U::IsConnected service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : bool, is connected
+ */
+static void IsConnected(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = false; // Not connected to ac:u service
+
+ LOG_WARNING(Service_AC, "(STUBBED) called");
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010000, nullptr, "CreateDefaultConfig"},
{0x00040006, nullptr, "ConnectAsync"},
@@ -44,7 +59,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002D0082, nullptr, "SetRequestEulaVersion"},
{0x00300004, nullptr, "RegisterDisconnectEvent"},
{0x003C0042, nullptr, "GetAPSSIDList"},
- {0x003E0042, nullptr, "IsConnected"},
+ {0x003E0042, IsConnected, "IsConnected"},
{0x00400042, nullptr, "SetClientVersion"},
};
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 360bcfca4..4d714037f 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -4,16 +4,287 @@
#include "common/logging/log.h"
-#include "core/hle/service/service.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/cam/cam_c.h"
#include "core/hle/service/cam/cam_q.h"
#include "core/hle/service/cam/cam_s.h"
#include "core/hle/service/cam/cam_u.h"
+#include "core/hle/service/service.h"
namespace Service {
namespace CAM {
+static const u32 TRANSFER_BYTES = 5 * 1024;
+
+static Kernel::SharedPtr<Kernel::Event> completion_event_cam1;
+static Kernel::SharedPtr<Kernel::Event> completion_event_cam2;
+static Kernel::SharedPtr<Kernel::Event> interrupt_error_event;
+static Kernel::SharedPtr<Kernel::Event> vsync_interrupt_error_event;
+
+void StartCapture(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port);
+}
+
+void StopCapture(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port);
+}
+
+void GetVsyncInterruptEvent(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = IPC::MoveHandleDesc();
+ cmd_buff[3] = Kernel::g_handle_table.Create(vsync_interrupt_error_event).MoveFrom();
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port);
+}
+
+void GetBufferErrorInterruptEvent(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x6, 1, 2);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = IPC::MoveHandleDesc();
+ cmd_buff[3] = Kernel::g_handle_table.Create(interrupt_error_event).MoveFrom();
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port);
+}
+
+void SetReceiving(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ VAddr dest = cmd_buff[1];
+ u8 port = cmd_buff[2] & 0xFF;
+ u32 image_size = cmd_buff[3];
+ u16 trans_unit = cmd_buff[4] & 0xFFFF;
+
+ Kernel::Event* completion_event = (Port)port == Port::Cam2 ?
+ completion_event_cam2.get() : completion_event_cam1.get();
+
+ completion_event->Signal();
+
+ cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = IPC::MoveHandleDesc();
+ cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom();
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, addr=0x%X, port=%d, image_size=%d, trans_unit=%d",
+ dest, port, image_size, trans_unit);
+}
+
+void SetTransferLines(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+ u16 transfer_lines = cmd_buff[2] & 0xFFFF;
+ u16 width = cmd_buff[3] & 0xFFFF;
+ u16 height = cmd_buff[4] & 0xFFFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, lines=%d, width=%d, height=%d",
+ port, transfer_lines, width, height);
+}
+
+void GetMaxLines(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u16 width = cmd_buff[1] & 0xFFFF;
+ u16 height = cmd_buff[2] & 0xFFFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = TRANSFER_BYTES / (2 * width);
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, width=%d, height=%d, lines = %d",
+ width, height, cmd_buff[2]);
+}
+
+void GetTransferBytes(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = TRANSFER_BYTES;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port);
+}
+
+void SetTrimming(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+ bool trim = (cmd_buff[2] & 0xFF) != 0;
+
+ cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trim=%d", port, trim);
+}
+
+void SetTrimmingParamsCenter(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 port = cmd_buff[1] & 0xFF;
+ s16 trimW = cmd_buff[2] & 0xFFFF;
+ s16 trimH = cmd_buff[3] & 0xFFFF;
+ s16 camW = cmd_buff[4] & 0xFFFF;
+ s16 camH = cmd_buff[5] & 0xFFFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trimW=%d, trimH=%d, camW=%d, camH=%d",
+ port, trimW, trimH, camW, camH);
+}
+
+void Activate(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 cam_select = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d",
+ cam_select);
+}
+
+void FlipImage(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 cam_select = cmd_buff[1] & 0xFF;
+ u8 flip = cmd_buff[2] & 0xFF;
+ u8 context = cmd_buff[3] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, flip=%d, context=%d",
+ cam_select, flip, context);
+}
+
+void SetSize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 cam_select = cmd_buff[1] & 0xFF;
+ u8 size = cmd_buff[2] & 0xFF;
+ u8 context = cmd_buff[3] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, size=%d, context=%d",
+ cam_select, size, context);
+}
+
+void SetFrameRate(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 cam_select = cmd_buff[1] & 0xFF;
+ u8 frame_rate = cmd_buff[2] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, frame_rate=%d",
+ cam_select, frame_rate);
+}
+
+void GetStereoCameraCalibrationData(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // Default values taken from yuriks' 3DS. Valid data is required here or games using the
+ // calibration get stuck in an infinite CPU loop.
+ StereoCameraCalibrationData data = {};
+ data.isValidRotationXY = 0;
+ data.scale = 1.001776f;
+ data.rotationZ = 0.008322907f;
+ data.translationX = -87.70484f;
+ data.translationY = -7.640977f;
+ data.rotationX = 0.0f;
+ data.rotationY = 0.0f;
+ data.angleOfViewRight = 64.66875f;
+ data.angleOfViewLeft = 64.76067f;
+ data.distanceToChart = 250.0f;
+ data.distanceCameras = 35.0f;
+ data.imageWidth = 640;
+ data.imageHeight = 480;
+
+ cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ memcpy(&cmd_buff[2], &data, sizeof(data));
+
+ LOG_TRACE(Service_CAM, "called");
+}
+
+void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called");
+}
+
+void PlayShutterSound(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u8 sound_id = cmd_buff[1] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x38, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id);
+}
+
+void DriverInitialize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ completion_event_cam1->Clear();
+ completion_event_cam2->Clear();
+ interrupt_error_event->Clear();
+ vsync_interrupt_error_event->Clear();
+
+ cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called");
+}
+
+void DriverFinalize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CAM, "(STUBBED) called");
+}
+
void Init() {
using namespace Kernel;
@@ -21,9 +292,18 @@ void Init() {
AddService(new CAM_Q_Interface);
AddService(new CAM_S_Interface);
AddService(new CAM_U_Interface);
+
+ completion_event_cam1 = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::completion_event_cam1");
+ completion_event_cam2 = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::completion_event_cam2");
+ interrupt_error_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::interrupt_error_event");
+ vsync_interrupt_error_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::vsync_interrupt_error_event");
}
void Shutdown() {
+ completion_event_cam1 = nullptr;
+ completion_event_cam2 = nullptr;
+ interrupt_error_event = nullptr;
+ vsync_interrupt_error_event = nullptr;
}
} // namespace CAM
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 23d0c9c59..2f4923728 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -4,7 +4,12 @@
#pragma once
+#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/swap.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
namespace Service {
namespace CAM {
@@ -140,6 +145,26 @@ enum class OutputFormat : u8 {
RGB565 = 1
};
+/// Stereo camera calibration data.
+struct StereoCameraCalibrationData {
+ u8 isValidRotationXY; ///< Bool indicating whether the X and Y rotation data is valid.
+ INSERT_PADDING_BYTES(3);
+ float_le scale; ///< Scale to match the left camera image with the right.
+ float_le rotationZ; ///< Z axis rotation to match the left camera image with the right.
+ float_le translationX; ///< X axis translation to match the left camera image with the right.
+ float_le translationY; ///< Y axis translation to match the left camera image with the right.
+ float_le rotationX; ///< X axis rotation to match the left camera image with the right.
+ float_le rotationY; ///< Y axis rotation to match the left camera image with the right.
+ float_le angleOfViewRight; ///< Right camera angle of view.
+ float_le angleOfViewLeft; ///< Left camera angle of view.
+ float_le distanceToChart; ///< Distance between cameras and measurement chart.
+ float_le distanceCameras; ///< Distance between left and right cameras.
+ s16_le imageWidth; ///< Image width.
+ s16_le imageHeight; ///< Image height.
+ INSERT_PADDING_BYTES(16);
+};
+static_assert(sizeof(StereoCameraCalibrationData) == 64, "StereoCameraCalibrationData structure size is wrong");
+
struct PackageParameterCameraSelect {
CameraSelect camera;
s8 exposure;
@@ -165,6 +190,243 @@ struct PackageParameterCameraSelect {
static_assert(sizeof(PackageParameterCameraSelect) == 28, "PackageParameterCameraSelect structure size is wrong");
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00010040
+ * 1: u8 Camera port (`Port` enum)
+ * Outputs:
+ * 0: 0x00010040
+ * 1: ResultCode
+ */
+void StartCapture(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00020040
+ * 1: u8 Camera port (`Port` enum)
+ * Outputs:
+ * 0: 0x00020040
+ * 1: ResultCode
+ */
+void StopCapture(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00050040
+ * 1: u8 Camera port (`Port` enum)
+ * Outputs:
+ * 0: 0x00050042
+ * 1: ResultCode
+ * 2: Descriptor: Handle
+ * 3: Event handle
+ */
+void GetVsyncInterruptEvent(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00060040
+ * 1: u8 Camera port (`Port` enum)
+ * Outputs:
+ * 0: 0x00060042
+ * 1: ResultCode
+ * 2: Descriptor: Handle
+ * 3: Event handle
+ */
+void GetBufferErrorInterruptEvent(Service::Interface* self);
+
+/**
+ * Sets the target buffer to receive a frame of image data and starts the transfer. Each camera
+ * port has its own event to signal the end of the transfer.
+ *
+ * Inputs:
+ * 0: 0x00070102
+ * 1: Destination address in calling process
+ * 2: u8 Camera port (`Port` enum)
+ * 3: Image size (in bytes?)
+ * 4: u16 Transfer unit size (in bytes?)
+ * 5: Descriptor: Handle
+ * 6: Handle to destination process
+ * Outputs:
+ * 0: 0x00070042
+ * 1: ResultCode
+ * 2: Descriptor: Handle
+ * 3: Handle to event signalled when transfer finishes
+ */
+void SetReceiving(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00090100
+ * 1: u8 Camera port (`Port` enum)
+ * 2: u16 Number of lines to transfer
+ * 3: u16 Width
+ * 4: u16 Height
+ * Outputs:
+ * 0: 0x00090040
+ * 1: ResultCode
+ */
+void SetTransferLines(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x000A0080
+ * 1: u16 Width
+ * 2: u16 Height
+ * Outputs:
+ * 0: 0x000A0080
+ * 1: ResultCode
+ * 2: Maximum number of lines that fit in the buffer(?)
+ */
+void GetMaxLines(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x000C0040
+ * 1: u8 Camera port (`Port` enum)
+ * Outputs:
+ * 0: 0x000C0080
+ * 1: ResultCode
+ * 2: Total number of bytes for each frame with current settings(?)
+ */
+void GetTransferBytes(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x000E0080
+ * 1: u8 Camera port (`Port` enum)
+ * 2: u8 bool Enable trimming if true
+ * Outputs:
+ * 0: 0x000E0040
+ * 1: ResultCode
+ */
+void SetTrimming(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00120140
+ * 1: u8 Camera port (`Port` enum)
+ * 2: s16 Trim width(?)
+ * 3: s16 Trim height(?)
+ * 4: s16 Camera width(?)
+ * 5: s16 Camera height(?)
+ * Outputs:
+ * 0: 0x00120040
+ * 1: ResultCode
+ */
+void SetTrimmingParamsCenter(Service::Interface* self);
+
+/**
+ * Selects up to two physical cameras to enable.
+ * Inputs:
+ * 0: 0x00130040
+ * 1: u8 Cameras to activate (`CameraSelect` enum)
+ * Outputs:
+ * 0: 0x00130040
+ * 1: ResultCode
+ */
+void Activate(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x001D00C0
+ * 1: u8 Camera select (`CameraSelect` enum)
+ * 2: u8 Type of flipping to perform (`Flip` enum)
+ * 3: u8 Context (`Context` enum)
+ * Outputs:
+ * 0: 0x001D0040
+ * 1: ResultCode
+ */
+void FlipImage(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x001F00C0
+ * 1: u8 Camera select (`CameraSelect` enum)
+ * 2: u8 Camera frame resolution (`Size` enum)
+ * 3: u8 Context id (`Context` enum)
+ * Outputs:
+ * 0: 0x001F0040
+ * 1: ResultCode
+ */
+void SetSize(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00200080
+ * 1: u8 Camera select (`CameraSelect` enum)
+ * 2: u8 Camera framerate (`FrameRate` enum)
+ * Outputs:
+ * 0: 0x00200040
+ * 1: ResultCode
+ */
+void SetFrameRate(Service::Interface* self);
+
+/**
+ * Returns calibration data relating the outside cameras to eachother, for use in AR applications.
+ *
+ * Inputs:
+ * 0: 0x002B0000
+ * Outputs:
+ * 0: 0x002B0440
+ * 1: ResultCode
+ * 2-17: `StereoCameraCalibrationData` structure with calibration values
+ */
+void GetStereoCameraCalibrationData(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00360000
+ * Outputs:
+ * 0: 0x00360080
+ * 1: ResultCode
+ * 2: ?
+ */
+void GetSuitableY2rStandardCoefficient(Service::Interface* self);
+
+/**
+ * Unknown
+ * Inputs:
+ * 0: 0x00380040
+ * 1: u8 Sound ID
+ * Outputs:
+ * 0: 0x00380040
+ * 1: ResultCode
+ */
+void PlayShutterSound(Service::Interface* self);
+
+/**
+ * Initializes the camera driver. Must be called before using other functions.
+ * Inputs:
+ * 0: 0x00390000
+ * Outputs:
+ * 0: 0x00390040
+ * 1: ResultCode
+ */
+void DriverInitialize(Service::Interface* self);
+
+/**
+ * Shuts down the camera driver.
+ * Inputs:
+ * 0: 0x003A0000
+ * Outputs:
+ * 0: 0x003A0040
+ * 1: ResultCode
+ */
+void DriverFinalize(Service::Interface* self);
+
/// Initialize CAM service(s)
void Init();
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp
index 9d59c55fb..a1070ebb2 100644
--- a/src/core/hle/service/cam/cam_u.cpp
+++ b/src/core/hle/service/cam/cam_u.cpp
@@ -2,31 +2,32 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/cam/cam.h"
#include "core/hle/service/cam/cam_u.h"
namespace Service {
namespace CAM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, nullptr, "StartCapture"},
- {0x00020040, nullptr, "StopCapture"},
+ {0x00010040, StartCapture, "StartCapture"},
+ {0x00020040, StopCapture, "StopCapture"},
{0x00030040, nullptr, "IsBusy"},
{0x00040040, nullptr, "ClearBuffer"},
- {0x00050040, nullptr, "GetVsyncInterruptEvent"},
- {0x00060040, nullptr, "GetBufferErrorInterruptEvent"},
- {0x00070102, nullptr, "SetReceiving"},
+ {0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"},
+ {0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"},
+ {0x00070102, SetReceiving, "SetReceiving"},
{0x00080040, nullptr, "IsFinishedReceiving"},
- {0x00090100, nullptr, "SetTransferLines"},
- {0x000A0080, nullptr, "GetMaxLines"},
+ {0x00090100, SetTransferLines, "SetTransferLines"},
+ {0x000A0080, GetMaxLines, "GetMaxLines"},
{0x000B0100, nullptr, "SetTransferBytes"},
- {0x000C0040, nullptr, "GetTransferBytes"},
+ {0x000C0040, GetTransferBytes, "GetTransferBytes"},
{0x000D0080, nullptr, "GetMaxBytes"},
- {0x000E0080, nullptr, "SetTrimming"},
+ {0x000E0080, SetTrimming, "SetTrimming"},
{0x000F0040, nullptr, "IsTrimming"},
{0x00100140, nullptr, "SetTrimmingParams"},
{0x00110040, nullptr, "GetTrimmingParams"},
- {0x00120140, nullptr, "SetTrimmingParamsCenter"},
- {0x00130040, nullptr, "Activate"},
+ {0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"},
+ {0x00130040, Activate, "Activate"},
{0x00140080, nullptr, "SwitchContext"},
{0x00150080, nullptr, "SetExposure"},
{0x00160080, nullptr, "SetWhiteBalance"},
@@ -36,10 +37,10 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x001A0040, nullptr, "IsAutoExposure"},
{0x001B0080, nullptr, "SetAutoWhiteBalance"},
{0x001C0040, nullptr, "IsAutoWhiteBalance"},
- {0x001D00C0, nullptr, "FlipImage"},
+ {0x001D00C0, FlipImage, "FlipImage"},
{0x001E0200, nullptr, "SetDetailSize"},
- {0x001F00C0, nullptr, "SetSize"},
- {0x00200080, nullptr, "SetFrameRate"},
+ {0x001F00C0, SetSize, "SetSize"},
+ {0x00200080, SetFrameRate, "SetFrameRate"},
{0x00210080, nullptr, "SetPhotoMode"},
{0x002200C0, nullptr, "SetEffect"},
{0x00230080, nullptr, "SetContrast"},
@@ -50,7 +51,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00280080, nullptr, "SetNoiseFilter"},
{0x00290080, nullptr, "SynchronizeVsyncTiming"},
{0x002A0080, nullptr, "GetLatestVsyncTiming"},
- {0x002B0000, nullptr, "GetStereoCameraCalibrationData"},
+ {0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
{0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
{0x002D00C0, nullptr, "WriteRegisterI2c"},
{0x002E00C0, nullptr, "WriteMcuVariableI2c"},
@@ -61,11 +62,11 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x003302C0, nullptr, "SetPackageParameterWithoutContext"},
{0x00340140, nullptr, "SetPackageParameterWithContext"},
{0x003501C0, nullptr, "SetPackageParameterWithContextDetail"},
- {0x00360000, nullptr, "GetSuitableY2rStandardCoefficient"},
+ {0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"},
{0x00370202, nullptr, "PlayShutterSoundWithWave"},
- {0x00380040, nullptr, "PlayShutterSound"},
- {0x00390000, nullptr, "DriverInitialize"},
- {0x003A0000, nullptr, "DriverFinalize"},
+ {0x00380040, PlayShutterSound, "PlayShutterSound"},
+ {0x00390000, DriverInitialize, "DriverInitialize"},
+ {0x003A0000, DriverFinalize, "DriverFinalize"},
{0x003B0000, nullptr, "GetActivatedCamera"},
{0x003C0000, nullptr, "GetSleepCamera"},
{0x003D0040, nullptr, "SetSleepCamera"},
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 15d3274ec..3ba24d466 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cinttypes>
+
#include "audio_core/hle/pipe.h"
+#include "common/hash.h"
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
@@ -55,18 +58,18 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
u32 addr = cmd_buff[1];
- cmd_buff[1] = 0; // No error
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
- LOG_TRACE(Service_DSP, "addr=0x%08X", addr);
+ LOG_DEBUG(Service_DSP, "addr=0x%08X", addr);
}
/**
* DSP_DSP::LoadComponent service function
* Inputs:
* 1 : Size
- * 2 : Unknown (observed only half word used)
- * 3 : Unknown (observed only half word used)
+ * 2 : Program mask (observed only half word used)
+ * 3 : Data mask (observed only half word used)
* 4 : (size << 4) | 0xA
* 5 : Buffer address
* Outputs:
@@ -77,18 +80,28 @@ static void LoadComponent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
- u32 unk1 = cmd_buff[2];
- u32 unk2 = cmd_buff[3];
- u32 new_size = cmd_buff[4];
+ u32 prog_mask = cmd_buff[2];
+ u32 data_mask = cmd_buff[3];
+ u32 desc = cmd_buff[4];
u32 buffer = cmd_buff[5];
- cmd_buff[1] = 0; // No error
+ cmd_buff[0] = IPC::MakeHeader(0x11, 2, 2);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
+ cmd_buff[3] = desc;
+ cmd_buff[4] = buffer;
// TODO(bunnei): Implement real DSP firmware loading
- LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, unk1=0x%08X, unk2=0x%08X, new_size=0x%X, buffer=0x%08X",
- size, unk1, unk2, new_size, buffer);
+ ASSERT(Memory::GetPointer(buffer) != nullptr);
+ ASSERT(size > 0x37C);
+
+ LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer), size));
+ // Some versions of the firmware have the location of DSP structures listed here.
+ LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer) + 0x340, 60));
+
+ LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X",
+ size, prog_mask, data_mask, buffer);
}
/**
@@ -129,8 +142,7 @@ static void FlushDataCache(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X",
- address, size, process);
+ LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process);
}
/**
@@ -154,14 +166,14 @@ static void RegisterInterruptEvents(Service::Interface* self) {
if (evt) {
interrupt_events[std::make_pair(interrupt, channel)] = evt;
cmd_buff[1] = RESULT_SUCCESS.raw;
- LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
+ LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
} else {
- cmd_buff[1] = -1;
- LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
+ LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
+ ASSERT(false); // This should really be handled at a IPC translation layer.
}
} else {
interrupt_events.erase(std::make_pair(interrupt, channel));
- LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
+ LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
}
}
@@ -175,7 +187,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
static void SetSemaphore(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- cmd_buff[1] = 0; // No error
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_DSP, "(STUBBED) called");
}
@@ -194,21 +206,12 @@ static void SetSemaphore(Service::Interface* self) {
static void WriteProcessPipe(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 channel = cmd_buff[1];
- u32 size = cmd_buff[2];
- u32 buffer = cmd_buff[4];
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 size = cmd_buff[2];
+ u32 buffer = cmd_buff[4];
- if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) {
- LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). channel=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], channel, size, buffer);
- cmd_buff[1] = -1; // TODO
- return;
- }
-
- if (!Memory::GetPointer(buffer)) {
- LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
- cmd_buff[1] = -1; // TODO
- return;
- }
+ ASSERT_MSG(IPC::StaticBufferDesc(size, 1) == cmd_buff[3], "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe, size, buffer);
+ ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
std::vector<u8> message(size);
@@ -216,11 +219,11 @@ static void WriteProcessPipe(Service::Interface* self) {
message[i] = Memory::Read8(buffer + i);
}
- DSP::HLE::PipeWrite(channel, message);
+ DSP::HLE::PipeWrite(pipe, message);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
+ LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
}
/**
@@ -232,7 +235,7 @@ static void WriteProcessPipe(Service::Interface* self) {
* 1 : Pipe Number
* 2 : Unknown
* 3 : Size in bytes of read (observed only lower half word used)
- * 0x41 : Virtual address to read from DSP pipe to in memory
+ * 0x41 : Virtual address of memory buffer to write pipe contents to
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Number of bytes read from pipe
@@ -240,25 +243,82 @@ static void WriteProcessPipe(Service::Interface* self) {
static void ReadPipeIfPossible(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 pipe = cmd_buff[1];
- u32 unk2 = cmd_buff[2];
- u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 unknown = cmd_buff[2];
+ u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size
VAddr addr = cmd_buff[0x41];
- if (!Memory::GetPointer(addr)) {
- LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr);
- cmd_buff[1] = -1; // TODO
- return;
+ ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
+ std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
+
+ Memory::WriteBlock(addr, response.data(), response.size());
+
+ cmd_buff[2] = static_cast<u32>(response.size());
+ } else {
+ cmd_buff[2] = 0; // Return no data
}
- std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
+ LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]);
+}
- Memory::WriteBlock(addr, response.data(), response.size());
+/**
+ * DSP_DSP::ReadPipe service function
+ * Inputs:
+ * 1 : Pipe Number
+ * 2 : Unknown
+ * 3 : Size in bytes of read (observed only lower half word used)
+ * 0x41 : Virtual address of memory buffer to write pipe contents to
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Number of bytes read from pipe
+ */
+static void ReadPipe(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 unknown = cmd_buff[2];
+ u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size
+ VAddr addr = cmd_buff[0x41];
+
+ ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
- cmd_buff[1] = 0; // No error
- cmd_buff[2] = (u32)response.size();
+ if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
+ std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
- LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr);
+ Memory::WriteBlock(addr, response.data(), response.size());
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = static_cast<u32>(response.size());
+ } else {
+ // No more data is in pipe. Hardware hangs in this case; this should never happen.
+ UNREACHABLE();
+ }
+
+ LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]);
+}
+
+/**
+ * DSP_DSP::GetPipeReadableSize service function
+ * Inputs:
+ * 1 : Pipe Number
+ * 2 : Unknown
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Number of bytes readable from pipe
+ */
+static void GetPipeReadableSize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 unknown = cmd_buff[2];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = DSP::HLE::GetPipeReadableSize(pipe);
+
+ LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, cmd_buff[2]);
}
/**
@@ -293,12 +353,73 @@ static void GetHeadphoneStatus(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0; // Not using headphones?
- LOG_DEBUG(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called");
+}
+
+/**
+ * DSP_DSP::RecvData service function
+ * This function reads a value out of a DSP register.
+ * Inputs:
+ * 1 : Register Number
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Value in the register
+ * Notes:
+ * This function has only been observed being called with a register number of 0.
+ */
+static void RecvData(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 register_number = cmd_buff[1];
+
+ ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
+
+ // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept.
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ switch (DSP::HLE::GetDspState()) {
+ case DSP::HLE::DspState::On:
+ cmd_buff[2] = 0;
+ break;
+ case DSP::HLE::DspState::Off:
+ case DSP::HLE::DspState::Sleeping:
+ cmd_buff[2] = 1;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ LOG_DEBUG(Service_DSP, "register_number=%u", register_number);
+}
+
+/**
+ * DSP_DSP::RecvDataIsReady service function
+ * This function checks whether a DSP register is ready to be read.
+ * Inputs:
+ * 1 : Register Number
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : non-zero == ready
+ * Note:
+ * This function has only been observed being called with a register number of 0.
+ */
+static void RecvDataIsReady(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 register_number = cmd_buff[1];
+
+ ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1; // Ready to read
+
+ LOG_DEBUG(Service_DSP, "register_number=%u", register_number);
}
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, nullptr, "RecvData"},
- {0x00020040, nullptr, "RecvDataIsReady"},
+ {0x00010040, RecvData, "RecvData"},
+ {0x00020040, RecvDataIsReady, "RecvDataIsReady"},
{0x00030080, nullptr, "SendData"},
{0x00040040, nullptr, "SendDataIsEmpty"},
{0x000500C2, nullptr, "SendFifoEx"},
@@ -310,8 +431,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
{0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
{0x000D0082, WriteProcessPipe, "WriteProcessPipe"},
- {0x000E00C0, nullptr, "ReadPipe"},
- {0x000F0080, nullptr, "GetPipeReadableSize"},
+ {0x000E00C0, ReadPipe, "ReadPipe"},
+ {0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"},
{0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
{0x001100C2, LoadComponent, "LoadComponent"},
{0x00120000, nullptr, "UnloadComponent"},
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 68b3f546e..93f21bec2 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -255,7 +255,8 @@ ResultStatus AppLoader_NCCH::Load() {
priority = exheader_header.arm11_system_local_caps.priority;
resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category;
- LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name);
+ LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name);
+ LOG_INFO(Loader, "Program ID: %016X" , ncch_header.program_id);
LOG_DEBUG(Loader, "Code compressed: %s" , is_compressed ? "yes" : "no");
LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
LOG_DEBUG(Loader, "Code size: 0x%08X", code_size);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 4753c63a7..7de5bd15d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -291,7 +291,7 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
} else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
return addr - VRAM_PADDR + VRAM_VADDR;
} else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
- return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapBase();
+ return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapAreaAddress();
} else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
} else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {