summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_core.cpp9
-rw-r--r--src/audio_core/hle/pipe.cpp32
-rw-r--r--src/audio_core/hle/pipe.h4
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/dsp_dsp.cpp191
-rw-r--r--src/core/hle/service/dsp_dsp.h19
-rw-r--r--src/core/hle/service/y2r_u.cpp480
-rw-r--r--src/core/hle/service/y2r_u.h20
9 files changed, 612 insertions, 146 deletions
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index 894f46990..b512b0f9b 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -4,6 +4,7 @@
#include "audio_core/audio_core.h"
#include "audio_core/hle/dsp.h"
+#include "audio_core/hle/pipe.h"
#include "core/core_timing.h"
#include "core/hle/kernel/vm_manager.h"
@@ -17,10 +18,10 @@ static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
if (DSP::HLE::Tick()) {
- // HACK: We're not signaling the interrups when they should be, but just firing them all off together.
- // It should be only (interrupt_id = 2, channel_id = 2) that's signalled here.
- // TODO(merry): Understand when the other interrupts are fired.
- DSP_DSP::SignalAllInterrupts();
+ // TODO(merry): Signal all the other interrupts as appropriate.
+ DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
+ // HACK(merry): Added to prevent regressions. Will remove soon.
+ DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Binary);
}
// Reschedule recurrent event
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
index 9381883b4..03280780f 100644
--- a/src/audio_core/hle/pipe.cpp
+++ b/src/audio_core/hle/pipe.cpp
@@ -12,12 +12,14 @@
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "core/hle/service/dsp_dsp.h"
+
namespace DSP {
namespace HLE {
static DspState dsp_state = DspState::Off;
-static std::array<std::vector<u8>, static_cast<size_t>(DspPipe::DspPipe_MAX)> pipe_data;
+static std::array<std::vector<u8>, NUM_DSP_PIPE> pipe_data;
void ResetPipes() {
for (auto& data : pipe_data) {
@@ -27,16 +29,18 @@ void ResetPipes() {
}
std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) {
- if (pipe_number >= DspPipe::DspPipe_MAX) {
- LOG_ERROR(Audio_DSP, "pipe_number = %u invalid", pipe_number);
+ const size_t pipe_index = static_cast<size_t>(pipe_number);
+
+ if (pipe_index >= NUM_DSP_PIPE) {
+ LOG_ERROR(Audio_DSP, "pipe_number = %zu invalid", pipe_index);
return {};
}
- std::vector<u8>& data = pipe_data[static_cast<size_t>(pipe_number)];
+ std::vector<u8>& data = pipe_data[pipe_index];
if (length > data.size()) {
- LOG_WARNING(Audio_DSP, "pipe_number = %u is out of data, application requested read of %u but %zu remain",
- pipe_number, length, data.size());
+ LOG_WARNING(Audio_DSP, "pipe_number = %zu is out of data, application requested read of %u but %zu remain",
+ pipe_index, length, data.size());
length = data.size();
}
@@ -49,16 +53,20 @@ std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) {
}
size_t GetPipeReadableSize(DspPipe pipe_number) {
- if (pipe_number >= DspPipe::DspPipe_MAX) {
- LOG_ERROR(Audio_DSP, "pipe_number = %u invalid", pipe_number);
+ const size_t pipe_index = static_cast<size_t>(pipe_number);
+
+ if (pipe_index >= NUM_DSP_PIPE) {
+ LOG_ERROR(Audio_DSP, "pipe_number = %zu invalid", pipe_index);
return 0;
}
- return pipe_data[static_cast<size_t>(pipe_number)].size();
+ return pipe_data[pipe_index].size();
}
static void WriteU16(DspPipe pipe_number, u16 value) {
- std::vector<u8>& data = pipe_data[static_cast<size_t>(pipe_number)];
+ const size_t pipe_index = static_cast<size_t>(pipe_number);
+
+ std::vector<u8>& data = pipe_data.at(pipe_index);
// Little endian
data.emplace_back(value & 0xFF);
data.emplace_back(value >> 8);
@@ -91,6 +99,8 @@ static void AudioPipeWriteStructAddresses() {
for (u16 addr : struct_addresses) {
WriteU16(DspPipe::Audio, addr);
}
+ // Signal that we have data on this pipe.
+ DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
}
void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
@@ -145,7 +155,7 @@ void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
return;
}
default:
- LOG_CRITICAL(Audio_DSP, "pipe_number = %u unimplemented", pipe_number);
+ LOG_CRITICAL(Audio_DSP, "pipe_number = %zu unimplemented", static_cast<size_t>(pipe_number));
UNIMPLEMENTED();
return;
}
diff --git a/src/audio_core/hle/pipe.h b/src/audio_core/hle/pipe.h
index 382d35e87..64d97f8ba 100644
--- a/src/audio_core/hle/pipe.h
+++ b/src/audio_core/hle/pipe.h
@@ -19,9 +19,9 @@ enum class DspPipe {
Debug = 0,
Dma = 1,
Audio = 2,
- Binary = 3,
- DspPipe_MAX
+ Binary = 3
};
+constexpr size_t NUM_DSP_PIPE = 8;
/**
* Read a DSP pipe.
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 6660d9879..cc9e0c624 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -92,7 +92,7 @@ else()
endif()
target_link_libraries(citra-qt core video_core audio_core common qhexedit)
target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
-target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
+target_link_libraries(citra-qt ${PLATFORM_LIBRARIES} Threads::Threads)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 2d22652d9..53931a106 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -18,6 +18,7 @@
/// Detailed description of the error. This listing is likely incomplete.
enum class ErrorDescription : u32 {
Success = 0,
+ OS_InvalidBufferDescriptor = 48,
WrongAddress = 53,
FS_NotFound = 120,
FS_AlreadyExists = 190,
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 08e437125..995bee3f9 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <cinttypes>
#include "audio_core/hle/pipe.h"
@@ -12,37 +13,80 @@
#include "core/hle/kernel/event.h"
#include "core/hle/service/dsp_dsp.h"
+using DspPipe = DSP::HLE::DspPipe;
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace DSP_DSP
namespace DSP_DSP {
-static u32 read_pipe_count;
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
-struct PairHash {
- template <typename T, typename U>
- std::size_t operator()(const std::pair<T, U> &x) const {
- // TODO(yuriks): Replace with better hash combining function.
- return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
+/// There are three types of interrupts
+enum class InterruptType {
+ Zero, One, Pipe
+};
+constexpr size_t NUM_INTERRUPT_TYPE = 3;
+
+class InterruptEvents final {
+public:
+ void Signal(InterruptType type, DspPipe pipe) {
+ Kernel::SharedPtr<Kernel::Event>& event = Get(type, pipe);
+ if (event) {
+ event->Signal();
+ }
}
+
+ Kernel::SharedPtr<Kernel::Event>& Get(InterruptType type, DspPipe dsp_pipe) {
+ switch (type) {
+ case InterruptType::Zero:
+ return zero;
+ case InterruptType::One:
+ return one;
+ case InterruptType::Pipe: {
+ const size_t pipe_index = static_cast<size_t>(dsp_pipe);
+ ASSERT(pipe_index < DSP::HLE::NUM_DSP_PIPE);
+ return pipe[pipe_index];
+ }
+ }
+
+ UNREACHABLE_MSG("Invalid interrupt type = %zu", static_cast<size_t>(type));
+ }
+
+ bool HasTooManyEventsRegistered() const {
+ // Actual service implementation only has 6 'slots' for interrupts.
+ constexpr size_t max_number_of_interrupt_events = 6;
+
+ size_t number = std::count_if(pipe.begin(), pipe.end(), [](const auto& evt) {
+ return evt != nullptr;
+ });
+
+ if (zero != nullptr)
+ number++;
+ if (one != nullptr)
+ number++;
+
+ return number >= max_number_of_interrupt_events;
+ }
+
+private:
+ /// Currently unknown purpose
+ Kernel::SharedPtr<Kernel::Event> zero = nullptr;
+ /// Currently unknown purpose
+ Kernel::SharedPtr<Kernel::Event> one = nullptr;
+ /// Each DSP pipe has an associated interrupt
+ std::array<Kernel::SharedPtr<Kernel::Event>, DSP::HLE::NUM_DSP_PIPE> pipe = {{}};
};
-/// Map of (audio interrupt number, channel number) to Kernel::Events. See: RegisterInterruptEvents
-static std::unordered_map<std::pair<u32, u32>, Kernel::SharedPtr<Kernel::Event>, PairHash> interrupt_events;
+static InterruptEvents interrupt_events;
// DSP Interrupts:
-// Interrupt #2 occurs every frame tick. Userland programs normally have a thread that's waiting
-// for an interrupt event. Immediately after this interrupt event, userland normally updates the
-// state in the next region and increments the relevant frame counter by two.
-void SignalAllInterrupts() {
- // HACK: The other interrupts have currently unknown purpose, we trigger them each tick in any case.
- for (auto& interrupt_event : interrupt_events)
- interrupt_event.second->Signal();
-}
-
-void SignalInterrupt(u32 interrupt, u32 channel) {
- interrupt_events[std::make_pair(interrupt, channel)]->Signal();
+// The audio-pipe interrupt occurs every frame tick. Userland programs normally have a thread
+// that's waiting for an interrupt event. Immediately after this interrupt event, userland
+// normally updates the state in the next region and increments the relevant frame counter by
+// two.
+void SignalPipeInterrupt(DspPipe pipe) {
+ interrupt_events.Signal(InterruptType::Pipe, pipe);
}
/**
@@ -58,7 +102,10 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
u32 addr = cmd_buff[1];
+ cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ // TODO(merry): There is a per-region offset missing in this calculation (that seems to be always zero).
cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
LOG_DEBUG(Service_DSP, "addr=0x%08X", addr);
@@ -113,7 +160,9 @@ static void LoadComponent(Service::Interface* self) {
static void GetSemaphoreEventHandle(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x16, 1, 2);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ // cmd_buff[2] not set
cmd_buff[3] = Kernel::g_handle_table.Create(semaphore_event).MoveFrom(); // Event handle
LOG_WARNING(Service_DSP, "(STUBBED) called");
@@ -138,8 +187,7 @@ static void FlushDataCache(Service::Interface* self) {
u32 size = cmd_buff[2];
u32 process = cmd_buff[4];
- // TODO(purpasmart96): Verify return header on HW
-
+ cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process);
@@ -148,8 +196,8 @@ static void FlushDataCache(Service::Interface* self) {
/**
* DSP_DSP::RegisterInterruptEvents service function
* Inputs:
- * 1 : Interrupt Number
- * 2 : Channel Number
+ * 1 : Interrupt Type
+ * 2 : Pipe Number
* 4 : Interrupt event handle
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
@@ -157,23 +205,40 @@ static void FlushDataCache(Service::Interface* self) {
static void RegisterInterruptEvents(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 interrupt = cmd_buff[1];
- u32 channel = cmd_buff[2];
+ u32 type_index = cmd_buff[1];
+ u32 pipe_index = cmd_buff[2];
u32 event_handle = cmd_buff[4];
+ ASSERT_MSG(type_index < NUM_INTERRUPT_TYPE && pipe_index < DSP::HLE::NUM_DSP_PIPE,
+ "Invalid type or pipe: type = %u, pipe = %u", type_index, pipe_index);
+
+ InterruptType type = static_cast<InterruptType>(cmd_buff[1]);
+ DspPipe pipe = static_cast<DspPipe>(cmd_buff[2]);
+
+ cmd_buff[0] = IPC::MakeHeader(0x15, 1, 0);
+
if (event_handle) {
auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
- if (evt) {
- interrupt_events[std::make_pair(interrupt, channel)] = evt;
- cmd_buff[1] = RESULT_SUCCESS.raw;
- LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
- } else {
- 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.
+
+ if (!evt) {
+ LOG_INFO(Service_DSP, "Invalid event handle! type=%u, pipe=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
+ ASSERT(false); // TODO: This should really be handled at an IPC translation layer.
+ }
+
+ if (interrupt_events.HasTooManyEventsRegistered()) {
+ LOG_INFO(Service_DSP, "Ran out of space to register interrupts (Attempted to register type=%u, pipe=%u, event_handle=0x%08X)",
+ type_index, pipe_index, event_handle);
+ cmd_buff[1] = ResultCode(ErrorDescription::InvalidResultValue, ErrorModule::DSP, ErrorSummary::OutOfResource, ErrorLevel::Status).raw;
+ return;
}
+
+ interrupt_events.Get(type, pipe) = evt;
+ LOG_INFO(Service_DSP, "Registered type=%u, pipe=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
} else {
- interrupt_events.erase(std::make_pair(interrupt, channel));
- LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
+ interrupt_events.Get(type, pipe) = nullptr;
+ LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
}
}
@@ -187,6 +252,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
static void SetSemaphore(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_DSP, "(STUBBED) called");
@@ -195,7 +261,7 @@ static void SetSemaphore(Service::Interface* self) {
/**
* DSP_DSP::WriteProcessPipe service function
* Inputs:
- * 1 : Channel
+ * 1 : Pipe Number
* 2 : Size
* 3 : (size << 14) | 0x402
* 4 : Buffer
@@ -206,24 +272,32 @@ static void SetSemaphore(Service::Interface* self) {
static void WriteProcessPipe(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 pipe_index = cmd_buff[1];
u32 size = cmd_buff[2];
u32 buffer = cmd_buff[4];
- 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);
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
- std::vector<u8> message(size);
+ if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) {
+ LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe_index, size, buffer);
+ cmd_buff[0] = IPC::MakeHeader(0, 1, 0);
+ cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
+ return;
+ }
+
+ ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe_index, size, buffer);
+ std::vector<u8> message(size);
for (size_t i = 0; i < size; i++) {
message[i] = Memory::Read8(buffer + i);
}
DSP::HLE::PipeWrite(pipe, message);
+ cmd_buff[0] = IPC::MakeHeader(0xD, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
+ LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe_index, size, buffer);
}
/**
@@ -243,13 +317,16 @@ static void WriteProcessPipe(Service::Interface* self) {
static void ReadPipeIfPossible(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 pipe_index = 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);
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
+
+ ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe_index, unknown, size, addr);
+ cmd_buff[0] = IPC::MakeHeader(0x10, 1, 2);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
@@ -260,8 +337,10 @@ static void ReadPipeIfPossible(Service::Interface* self) {
} else {
cmd_buff[2] = 0; // Return no data
}
+ cmd_buff[3] = IPC::StaticBufferDesc(size, 0);
+ cmd_buff[4] = addr;
- 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]);
+ LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe_index, unknown, size, addr, cmd_buff[2]);
}
/**
@@ -278,26 +357,31 @@ static void ReadPipeIfPossible(Service::Interface* self) {
static void ReadPipe(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 pipe_index = 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);
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
+
+ ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe_index, unknown, size, addr);
if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
Memory::WriteBlock(addr, response.data(), response.size());
+ cmd_buff[0] = IPC::MakeHeader(0xE, 2, 2);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = static_cast<u32>(response.size());
+ cmd_buff[3] = IPC::StaticBufferDesc(size, 0);
+ cmd_buff[4] = addr;
} 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]);
+ LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe_index, unknown, size, addr, cmd_buff[2]);
}
/**
@@ -312,13 +396,16 @@ static void ReadPipe(Service::Interface* self) {
static void GetPipeReadableSize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
+ u32 pipe_index = cmd_buff[1];
u32 unknown = cmd_buff[2];
+ DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
+
+ cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
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]);
+ LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe_index, unknown, cmd_buff[2]);
}
/**
@@ -333,6 +420,7 @@ static void SetSemaphoreMask(Service::Interface* self) {
u32 mask = cmd_buff[1];
+ cmd_buff[0] = IPC::MakeHeader(0x17, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_DSP, "(STUBBED) called mask=0x%08X", mask);
@@ -350,6 +438,7 @@ static void SetSemaphoreMask(Service::Interface* self) {
static void GetHeadphoneStatus(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x1F, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0; // Not using headphones?
@@ -376,6 +465,7 @@ static void RecvData(Service::Interface* self) {
// Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept.
+ cmd_buff[0] = IPC::MakeHeader(0x1, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
switch (DSP::HLE::GetDspState()) {
case DSP::HLE::DspState::On:
@@ -411,6 +501,7 @@ static void RecvDataIsReady(Service::Interface* self) {
ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
+ cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 1; // Ready to read
@@ -458,14 +549,14 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
semaphore_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "DSP_DSP::semaphore_event");
- read_pipe_count = 0;
+ interrupt_events = {};
Register(FunctionTable);
}
Interface::~Interface() {
semaphore_event = nullptr;
- interrupt_events.clear();
+ interrupt_events = {};
}
} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index 32b89e9bb..22f6687cc 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -8,6 +8,12 @@
#include "core/hle/service/service.h"
+namespace DSP {
+namespace HLE {
+enum class DspPipe;
+}
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace DSP_DSP
@@ -23,15 +29,10 @@ public:
}
};
-/// Signal all audio related interrupts.
-void SignalAllInterrupts();
-
/**
- * Signal a specific audio related interrupt based on interrupt id and channel id.
- * @param interrupt_id The interrupt id
- * @param channel_id The channel id
- * The significance of various values of interrupt_id and channel_id is not yet known.
+ * Signal a specific DSP related interrupt of type == InterruptType::Pipe, pipe == pipe.
+ * @param pipe The DSP pipe for which to signal an interrupt for.
*/
-void SignalInterrupt(u32 interrupt_id, u32 channel_id);
+void SignalPipeInterrupt(DSP::HLE::DspPipe pipe);
-} // namespace
+} // namespace DSP_DSP
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 1672ad775..d16578f87 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -4,6 +4,7 @@
#include <cstring>
+#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/logging/log.h"
@@ -25,13 +26,17 @@ struct ConversionParameters {
u16 input_line_width;
u16 input_lines;
StandardCoefficient standard_coefficient;
- u8 reserved;
+ u8 padding;
u16 alpha;
};
static_assert(sizeof(ConversionParameters) == 12, "ConversionParameters struct has incorrect size");
static Kernel::SharedPtr<Kernel::Event> completion_event;
static ConversionConfiguration conversion;
+static DitheringWeightParams dithering_weight_params;
+static u32 temporal_dithering_enabled = 0;
+static u32 transfer_end_interrupt_enabled = 0;
+static u32 spacial_dithering_enabled = 0;
static const CoefficientSet standard_coefficients[4] = {
{{ 0x100, 0x166, 0xB6, 0x58, 0x1C5, -0x166F, 0x10EE, -0x1C5B }}, // ITU_Rec601
@@ -70,7 +75,7 @@ ResultCode ConversionConfiguration::SetInputLines(u16 lines) {
ResultCode ConversionConfiguration::SetStandardCoefficient(StandardCoefficient standard_coefficient) {
size_t index = static_cast<size_t>(standard_coefficient);
- if (index >= 4) {
+ if (index >= ARRAY_SIZE(standard_coefficients)) {
return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053ED
}
@@ -83,44 +88,183 @@ static void SetInputFormat(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.input_format = static_cast<InputFormat>(cmd_buff[1]);
+
+ cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
+}
+static void GetInputFormat(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(conversion.input_format);
+
+ LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
}
static void SetOutputFormat(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.output_format = static_cast<OutputFormat>(cmd_buff[1]);
+
+ cmd_buff[0] = IPC::MakeHeader(0x3, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
+}
+
+static void GetOutputFormat(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x4, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(conversion.output_format);
+
+ LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
}
static void SetRotation(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.rotation = static_cast<Rotation>(cmd_buff[1]);
+
+ cmd_buff[0] = IPC::MakeHeader(0x5, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
+}
+
+static void GetRotation(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x6, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(conversion.rotation);
+
+ LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
}
static void SetBlockAlignment(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.block_alignment = static_cast<BlockAlignment>(cmd_buff[1]);
- LOG_DEBUG(Service_Y2R, "called alignment=%hhu", conversion.block_alignment);
+ cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment);
+}
+
+static void GetBlockAlignment(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(conversion.block_alignment);
+
+ LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment);
+}
+
+/**
+ * Y2R_U::SetSpacialDithering service function
+ * Inputs:
+ * 1 : u8, 0 = Disabled, 1 = Enabled
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void SetSpacialDithering(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ spacial_dithering_enabled = cmd_buff[1] & 0xF;
+
+ cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R_U::GetSpacialDithering service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Disabled, 1 = Enabled
+ */
+static void GetSpacialDithering(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = spacial_dithering_enabled;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R_U::SetTemporalDithering service function
+ * Inputs:
+ * 1 : u8, 0 = Disabled, 1 = Enabled
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void SetTemporalDithering(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ temporal_dithering_enabled = cmd_buff[1] & 0xF;
+
+ cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R_U::GetTemporalDithering service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Disabled, 1 = Enabled
+ */
+static void GetTemporalDithering(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = temporal_dithering_enabled;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
+/**
+ * Y2R_U::SetTransferEndInterrupt service function
+ * Inputs:
+ * 1 : u8, 0 = Disabled, 1 = Enabled
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
static void SetTransferEndInterrupt(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ transfer_end_interrupt_enabled = cmd_buff[1] & 0xf;
cmd_buff[0] = IPC::MakeHeader(0xD, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
- LOG_DEBUG(Service_Y2R, "(STUBBED) called");
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R_U::GetTransferEndInterrupt service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Disabled, 1 = Enabled
+ */
+static void GetTransferEndInterrupt(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0xE, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = transfer_end_interrupt_enabled;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
/**
@@ -132,8 +276,10 @@ static void SetTransferEndInterrupt(Service::Interface* self) {
static void GetTransferEndEvent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom();
+
LOG_DEBUG(Service_Y2R, "called");
}
@@ -144,12 +290,12 @@ static void SetSendingY(Service::Interface* self) {
conversion.src_Y.image_size = cmd_buff[2];
conversion.src_Y.transfer_unit = cmd_buff[3];
conversion.src_Y.gap = cmd_buff[4];
- u32 src_process_handle = cmd_buff[6];
- LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
- "src_process_handle=0x%08X", conversion.src_Y.image_size,
- conversion.src_Y.transfer_unit, conversion.src_Y.gap, src_process_handle);
+ cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, src_process_handle=0x%08X",
+ conversion.src_Y.image_size, conversion.src_Y.transfer_unit, conversion.src_Y.gap, cmd_buff[6]);
}
static void SetSendingU(Service::Interface* self) {
@@ -159,12 +305,12 @@ static void SetSendingU(Service::Interface* self) {
conversion.src_U.image_size = cmd_buff[2];
conversion.src_U.transfer_unit = cmd_buff[3];
conversion.src_U.gap = cmd_buff[4];
- u32 src_process_handle = cmd_buff[6];
- LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
- "src_process_handle=0x%08X", conversion.src_U.image_size,
- conversion.src_U.transfer_unit, conversion.src_U.gap, src_process_handle);
+ cmd_buff[0] = IPC::MakeHeader(0x11, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, src_process_handle=0x%08X",
+ conversion.src_U.image_size, conversion.src_U.transfer_unit, conversion.src_U.gap, cmd_buff[6]);
}
static void SetSendingV(Service::Interface* self) {
@@ -174,12 +320,12 @@ static void SetSendingV(Service::Interface* self) {
conversion.src_V.image_size = cmd_buff[2];
conversion.src_V.transfer_unit = cmd_buff[3];
conversion.src_V.gap = cmd_buff[4];
- u32 src_process_handle = cmd_buff[6];
- LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
- "src_process_handle=0x%08X", conversion.src_V.image_size,
- conversion.src_V.transfer_unit, conversion.src_V.gap, src_process_handle);
+ cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, src_process_handle=0x%08X",
+ conversion.src_V.image_size, conversion.src_V.transfer_unit, conversion.src_V.gap, cmd_buff[6]);
}
static void SetSendingYUYV(Service::Interface* self) {
@@ -189,12 +335,76 @@ static void SetSendingYUYV(Service::Interface* self) {
conversion.src_YUYV.image_size = cmd_buff[2];
conversion.src_YUYV.transfer_unit = cmd_buff[3];
conversion.src_YUYV.gap = cmd_buff[4];
- u32 src_process_handle = cmd_buff[6];
- LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
- "src_process_handle=0x%08X", conversion.src_YUYV.image_size,
- conversion.src_YUYV.transfer_unit, conversion.src_YUYV.gap, src_process_handle);
+ cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, src_process_handle=0x%08X",
+ conversion.src_YUYV.image_size, conversion.src_YUYV.transfer_unit, conversion.src_YUYV.gap, cmd_buff[6]);
+}
+
+/**
+ * Y2R::IsFinishedSendingYuv service function
+ * Output:
+ * 1 : Result of the function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Not Finished, 1 = Finished
+ */
+static void IsFinishedSendingYuv(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x14, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R::IsFinishedSendingY service function
+ * Output:
+ * 1 : Result of the function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Not Finished, 1 = Finished
+ */
+static void IsFinishedSendingY(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x15, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R::IsFinishedSendingU service function
+ * Output:
+ * 1 : Result of the function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Not Finished, 1 = Finished
+ */
+static void IsFinishedSendingU(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
+}
+
+/**
+ * Y2R::IsFinishedSendingV service function
+ * Output:
+ * 1 : Result of the function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Not Finished, 1 = Finished
+ */
+static void IsFinishedSendingV(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x17, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
static void SetReceiving(Service::Interface* self) {
@@ -204,27 +414,66 @@ static void SetReceiving(Service::Interface* self) {
conversion.dst.image_size = cmd_buff[2];
conversion.dst.transfer_unit = cmd_buff[3];
conversion.dst.gap = cmd_buff[4];
- u32 dst_process_handle = cmd_buff[6];
- LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
- "dst_process_handle=0x%08X", conversion.dst.image_size,
- conversion.dst.transfer_unit, conversion.dst.gap,
- dst_process_handle);
+ cmd_buff[0] = IPC::MakeHeader(0x18, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, dst_process_handle=0x%08X",
+ conversion.dst.image_size, conversion.dst.transfer_unit, conversion.dst.gap, cmd_buff[6]);
+}
+
+/**
+ * Y2R::IsFinishedReceiving service function
+ * Output:
+ * 1 : Result of the function, 0 on success, otherwise error code
+ * 2 : u8, 0 = Not Finished, 1 = Finished
+ */
+static void IsFinishedReceiving(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x19, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1;
+
+ LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
static void SetInputLineWidth(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]);
+ cmd_buff[0] = IPC::MakeHeader(0x1A, 1, 0);
cmd_buff[1] = conversion.SetInputLineWidth(cmd_buff[1]).raw;
+
+ LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]);
+}
+
+static void GetInputLineWidth(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x1B, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = conversion.input_line_width;
+
+ LOG_DEBUG(Service_Y2R, "called input_line_width=%u", conversion.input_line_width);
}
static void SetInputLines(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- LOG_DEBUG(Service_Y2R, "called input_line_number=%u", cmd_buff[1]);
+ cmd_buff[0] = IPC::MakeHeader(0x1C, 1, 0);
cmd_buff[1] = conversion.SetInputLines(cmd_buff[1]).raw;
+
+ LOG_DEBUG(Service_Y2R, "called input_lines=%u", cmd_buff[1]);
+}
+
+static void GetInputLines(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x1D, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(conversion.input_lines);
+
+ LOG_DEBUG(Service_Y2R, "called input_lines=%u", conversion.input_lines);
}
static void SetCoefficient(Service::Interface* self) {
@@ -232,44 +481,111 @@ static void SetCoefficient(Service::Interface* self) {
const u16* coefficients = reinterpret_cast<const u16*>(&cmd_buff[1]);
std::memcpy(conversion.coefficients.data(), coefficients, sizeof(CoefficientSet));
+
+ cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
LOG_DEBUG(Service_Y2R, "called coefficients=[%hX, %hX, %hX, %hX, %hX, %hX, %hX, %hX]",
coefficients[0], coefficients[1], coefficients[2], coefficients[3],
coefficients[4], coefficients[5], coefficients[6], coefficients[7]);
+}
+
+static void GetCoefficient(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x1F, 5, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+ std::memcpy(&cmd_buff[2], conversion.coefficients.data(), sizeof(CoefficientSet));
+
+ LOG_DEBUG(Service_Y2R, "called");
}
static void SetStandardCoefficient(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", cmd_buff[1]);
+ u32 index = cmd_buff[1];
+
+ cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
+ cmd_buff[1] = conversion.SetStandardCoefficient((StandardCoefficient)index).raw;
- cmd_buff[1] = conversion.SetStandardCoefficient((StandardCoefficient)cmd_buff[1]).raw;
+ LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", index);
+}
+
+static void GetStandardCoefficient(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 index = cmd_buff[1];
+
+ if (index < ARRAY_SIZE(standard_coefficients)) {
+ cmd_buff[0] = IPC::MakeHeader(0x21, 5, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ std::memcpy(&cmd_buff[2], &standard_coefficients[index], sizeof(CoefficientSet));
+
+ LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u ", index);
+ } else {
+ cmd_buff[0] = IPC::MakeHeader(0x21, 1, 0);
+ cmd_buff[1] = -1; // TODO(bunnei): Identify the correct error code for this
+
+ LOG_ERROR(Service_Y2R, "called standard_coefficient=%u The argument is invalid!", index);
+ }
}
static void SetAlpha(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.alpha = cmd_buff[1];
+
+ cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
+}
+
+static void GetAlpha(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x23, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = conversion.alpha;
+
LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
+}
+
+static void SetDitheringWeightParams(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ std::memcpy(&dithering_weight_params, &cmd_buff[1], sizeof(DitheringWeightParams));
+ cmd_buff[0] = IPC::MakeHeader(0x24, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called");
+}
+
+static void GetDitheringWeightParams(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x25, 9, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ std::memcpy(&cmd_buff[2], &dithering_weight_params, sizeof(DitheringWeightParams));
+
+ LOG_DEBUG(Service_Y2R, "called");
}
static void StartConversion(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
- u32 total_output_size = conversion.input_lines *
- (conversion.dst.transfer_unit + conversion.dst.gap);
+ u32 total_output_size = conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap);
Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size);
HW::Y2R::PerformConversion(conversion);
- LOG_DEBUG(Service_Y2R, "called");
completion_event->Signal();
+ cmd_buff[0] = IPC::MakeHeader(0x26, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called");
}
static void StopConversion(Service::Interface* self) {
@@ -277,6 +593,7 @@ static void StopConversion(Service::Interface* self) {
cmd_buff[0] = IPC::MakeHeader(0x27, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
LOG_DEBUG(Service_Y2R, "called");
}
@@ -289,50 +606,61 @@ static void StopConversion(Service::Interface* self) {
static void IsBusyConversion(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x28, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0; // StartConversion always finishes immediately
+
LOG_DEBUG(Service_Y2R, "called");
}
/**
- * Y2R_U::SetConversionParams service function
+ * Y2R_U::SetPackageParameter service function
*/
-static void SetConversionParams(Service::Interface* self) {
+static void SetPackageParameter(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
auto params = reinterpret_cast<const ConversionParameters*>(&cmd_buff[1]);
- LOG_DEBUG(Service_Y2R,
- "called input_format=%hhu output_format=%hhu rotation=%hhu block_alignment=%hhu "
- "input_line_width=%hu input_lines=%hu standard_coefficient=%hhu "
- "reserved=%hhu alpha=%hX",
- params->input_format, params->output_format, params->rotation, params->block_alignment,
- params->input_line_width, params->input_lines, params->standard_coefficient,
- params->reserved, params->alpha);
-
- ResultCode result = RESULT_SUCCESS;
conversion.input_format = params->input_format;
conversion.output_format = params->output_format;
conversion.rotation = params->rotation;
conversion.block_alignment = params->block_alignment;
- result = conversion.SetInputLineWidth(params->input_line_width);
- if (result.IsError()) goto cleanup;
+
+ ResultCode result = conversion.SetInputLineWidth(params->input_line_width);
+
+ if (result.IsError())
+ goto cleanup;
+
result = conversion.SetInputLines(params->input_lines);
- if (result.IsError()) goto cleanup;
+
+ if (result.IsError())
+ goto cleanup;
+
result = conversion.SetStandardCoefficient(params->standard_coefficient);
- if (result.IsError()) goto cleanup;
+
+ if (result.IsError())
+ goto cleanup;
+
+ conversion.padding = params->padding;
conversion.alpha = params->alpha;
cleanup:
cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0);
cmd_buff[1] = result.raw;
+
+ LOG_DEBUG(Service_Y2R, "called input_format=%hhu output_format=%hhu rotation=%hhu block_alignment=%hhu "
+ "input_line_width=%hu input_lines=%hu standard_coefficient=%hhu reserved=%hhu alpha=%hX",
+ params->input_format, params->output_format, params->rotation, params->block_alignment,
+ params->input_line_width, params->input_lines, params->standard_coefficient, params->padding, params->alpha);
}
static void PingProcess(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x2A, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0;
+
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
@@ -358,6 +686,7 @@ static void DriverInitialize(Service::Interface* self) {
cmd_buff[0] = IPC::MakeHeader(0x2B, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
LOG_DEBUG(Service_Y2R, "called");
}
@@ -366,54 +695,67 @@ static void DriverFinalize(Service::Interface* self) {
cmd_buff[0] = IPC::MakeHeader(0x2C, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_Y2R, "called");
+}
+
+
+static void GetPackageParameter(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x2D, 4, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ std::memcpy(&cmd_buff[2], &conversion, sizeof(ConversionParameters));
+
LOG_DEBUG(Service_Y2R, "called");
}
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, SetInputFormat, "SetInputFormat"},
- {0x00020000, nullptr, "GetInputFormat"},
+ {0x00020000, GetInputFormat, "GetInputFormat"},
{0x00030040, SetOutputFormat, "SetOutputFormat"},
- {0x00040000, nullptr, "GetOutputFormat"},
+ {0x00040000, GetOutputFormat, "GetOutputFormat"},
{0x00050040, SetRotation, "SetRotation"},
- {0x00060000, nullptr, "GetRotation"},
+ {0x00060000, GetRotation, "GetRotation"},
{0x00070040, SetBlockAlignment, "SetBlockAlignment"},
- {0x00080000, nullptr, "GetBlockAlignment"},
- {0x00090040, nullptr, "SetSpacialDithering"},
- {0x000A0000, nullptr, "GetSpacialDithering"},
- {0x000B0040, nullptr, "SetTemporalDithering"},
- {0x000C0000, nullptr, "GetTemporalDithering"},
+ {0x00080000, GetBlockAlignment, "GetBlockAlignment"},
+ {0x00090040, SetSpacialDithering, "SetSpacialDithering"},
+ {0x000A0000, GetSpacialDithering, "GetSpacialDithering"},
+ {0x000B0040, SetTemporalDithering, "SetTemporalDithering"},
+ {0x000C0000, GetTemporalDithering, "GetTemporalDithering"},
{0x000D0040, SetTransferEndInterrupt, "SetTransferEndInterrupt"},
+ {0x000E0000, GetTransferEndInterrupt, "GetTransferEndInterrupt"},
{0x000F0000, GetTransferEndEvent, "GetTransferEndEvent"},
{0x00100102, SetSendingY, "SetSendingY"},
{0x00110102, SetSendingU, "SetSendingU"},
{0x00120102, SetSendingV, "SetSendingV"},
{0x00130102, SetSendingYUYV, "SetSendingYUYV"},
- {0x00140000, nullptr, "IsFinishedSendingYuv"},
- {0x00150000, nullptr, "IsFinishedSendingY"},
- {0x00160000, nullptr, "IsFinishedSendingU"},
- {0x00170000, nullptr, "IsFinishedSendingV"},
+ {0x00140000, IsFinishedSendingYuv, "IsFinishedSendingYuv"},
+ {0x00150000, IsFinishedSendingY, "IsFinishedSendingY"},
+ {0x00160000, IsFinishedSendingU, "IsFinishedSendingU"},
+ {0x00170000, IsFinishedSendingV, "IsFinishedSendingV"},
{0x00180102, SetReceiving, "SetReceiving"},
- {0x00190000, nullptr, "IsFinishedReceiving"},
+ {0x00190000, IsFinishedReceiving, "IsFinishedReceiving"},
{0x001A0040, SetInputLineWidth, "SetInputLineWidth"},
- {0x001B0000, nullptr, "GetInputLineWidth"},
+ {0x001B0000, GetInputLineWidth, "GetInputLineWidth"},
{0x001C0040, SetInputLines, "SetInputLines"},
- {0x001D0000, nullptr, "GetInputLines"},
+ {0x001D0000, GetInputLines, "GetInputLines"},
{0x001E0100, SetCoefficient, "SetCoefficient"},
- {0x001F0000, nullptr, "GetCoefficient"},
+ {0x001F0000, GetCoefficient, "GetCoefficient"},
{0x00200040, SetStandardCoefficient, "SetStandardCoefficient"},
- {0x00210040, nullptr, "GetStandardCoefficientParams"},
+ {0x00210040, GetStandardCoefficient, "GetStandardCoefficient"},
{0x00220040, SetAlpha, "SetAlpha"},
- {0x00230000, nullptr, "GetAlpha"},
- {0x00240200, nullptr, "SetDitheringWeightParams"},
- {0x00250000, nullptr, "GetDitheringWeightParams"},
+ {0x00230000, GetAlpha, "GetAlpha"},
+ {0x00240200, SetDitheringWeightParams,"SetDitheringWeightParams"},
+ {0x00250000, GetDitheringWeightParams,"GetDitheringWeightParams"},
{0x00260000, StartConversion, "StartConversion"},
{0x00270000, StopConversion, "StopConversion"},
{0x00280000, IsBusyConversion, "IsBusyConversion"},
- {0x002901C0, SetConversionParams, "SetConversionParams"},
+ {0x002901C0, SetPackageParameter, "SetPackageParameter"},
{0x002A0000, PingProcess, "PingProcess"},
{0x002B0000, DriverInitialize, "DriverInitialize"},
{0x002C0000, DriverFinalize, "DriverFinalize"},
- {0x002D0000, nullptr, "GetPackageParameter"},
+ {0x002D0000, GetPackageParameter, "GetPackageParameter"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 3965a5545..95fa2fdb7 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -97,6 +97,7 @@ struct ConversionConfiguration {
u16 input_line_width;
u16 input_lines;
CoefficientSet coefficients;
+ u8 padding;
u16 alpha;
/// Input parameters for the Y (luma) plane
@@ -109,6 +110,25 @@ struct ConversionConfiguration {
ResultCode SetStandardCoefficient(StandardCoefficient standard_coefficient);
};
+struct DitheringWeightParams {
+ u16 w0_xEven_yEven;
+ u16 w0_xOdd_yEven;
+ u16 w0_xEven_yOdd;
+ u16 w0_xOdd_yOdd;
+ u16 w1_xEven_yEven;
+ u16 w1_xOdd_yEven;
+ u16 w1_xEven_yOdd;
+ u16 w1_xOdd_yOdd;
+ u16 w2_xEven_yEven;
+ u16 w2_xOdd_yEven;
+ u16 w2_xEven_yOdd;
+ u16 w2_xOdd_yOdd;
+ u16 w3_xEven_yEven;
+ u16 w3_xOdd_yEven;
+ u16 w3_xEven_yOdd;
+ u16 w3_xOdd_yOdd;
+};
+
class Interface : public Service::Interface {
public:
Interface();