diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 766fff1b0..8d52f2405 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -3,10 +3,6 @@ // Refer to the license.txt file included. #include -#include -#include -#include -#include #include "common/bit_set.h" #include "common/logging/log.h" #include "core/core_timing.h" @@ -14,78 +10,18 @@ #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" -#include "core/hle/result.h" +#include "core/hle/kernel/process.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" #include "core/memory.h" #include "core/settings.h" namespace Service { namespace CAM { -namespace { - -struct ContextConfig { - Flip flip; - Effect effect; - OutputFormat format; - Resolution resolution; -}; - -struct CameraConfig { - std::unique_ptr impl; - std::array contexts; - int current_context; - FrameRate frame_rate; -}; - -struct PortConfig { - int camera_id; - - bool is_active; // set when the port is activated by an Activate call. - bool is_pending_receiving; // set if SetReceiving is called when is_busy = false. When - // StartCapture is called then, this will trigger a receiving - // process and reset itself. - bool is_busy; // set when StartCapture is called and reset when StopCapture is called. - bool is_receiving; // set when there is an ongoing receiving process. - - bool is_trimming; - u16 x0; // x-coordinate of starting position for trimming - u16 y0; // y-coordinate of starting position for trimming - u16 x1; // x-coordinate of ending position for trimming - u16 y1; // y-coordinate of ending position for trimming - - u16 transfer_bytes; - - Kernel::SharedPtr completion_event; - Kernel::SharedPtr buffer_error_interrupt_event; - Kernel::SharedPtr vsync_interrupt_event; - - std::future> capture_result; // will hold the received frame. - VAddr dest; // the destination address of a receiving process - u32 dest_size; // the destination size of a receiving process - - void Clear() { - completion_event->Clear(); - buffer_error_interrupt_event->Clear(); - vsync_interrupt_event->Clear(); - is_receiving = false; - is_active = false; - is_pending_receiving = false; - is_busy = false; - is_trimming = false; - x0 = 0; - y0 = 0; - x1 = 0; - y1 = 0; - transfer_bytes = 256; - } -}; - // built-in resolution parameters constexpr std::array PRESET_RESOLUTION{{ {640, 480, 0, 0, 639, 479}, // VGA @@ -115,16 +51,28 @@ constexpr std::array LATENCY_BY_FRAME_RATE{{ 33, // Rate_30_To_10 }}; -std::array cameras; -std::array ports; -CoreTiming::EventType* completion_event_callback; - const ResultCode ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM, ErrorSummary::InvalidArgument, ErrorLevel::Usage); const ResultCode ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM, ErrorSummary::InvalidArgument, ErrorLevel::Usage); -void CompletionEventCallBack(u64 port_id, int) { +void Module::PortConfig::Clear() { + completion_event->Clear(); + buffer_error_interrupt_event->Clear(); + vsync_interrupt_event->Clear(); + is_receiving = false; + is_active = false; + is_pending_receiving = false; + is_busy = false; + is_trimming = false; + x0 = 0; + y0 = 0; + x1 = 0; + y1 = 0; + transfer_bytes = 256; +} + +void Module::CompletionEventCallBack(u64 port_id, int) { PortConfig& port = ports[port_id]; const CameraConfig& camera = cameras[port.camera_id]; const auto buffer = port.capture_result.get(); @@ -165,7 +113,7 @@ void CompletionEventCallBack(u64 port_id, int) { if (copy_length <= 0) { break; } - Memory::WriteBlock(dest_ptr, src_ptr, copy_length); + Memory::WriteBlock(*port.dest_process, dest_ptr, src_ptr, copy_length); dest_ptr += copy_length; dest_size_left -= copy_length; src_ptr += original_width; @@ -177,16 +125,15 @@ void CompletionEventCallBack(u64 port_id, int) { LOG_ERROR(Service_CAM, "The destination size (%u) doesn't match the source (%zu)!", port.dest_size, buffer_size); } - Memory::WriteBlock(port.dest, buffer.data(), std::min(port.dest_size, buffer_size)); + Memory::WriteBlock(*port.dest_process, port.dest, buffer.data(), + std::min(port.dest_size, buffer_size)); } port.is_receiving = false; port.completion_event->Signal(); } -// Starts a receiving process on the specified port. This can only be called when is_busy = true and -// is_receiving = false. -void StartReceiving(int port_id) { +void Module::StartReceiving(int port_id) { PortConfig& port = ports[port_id]; port.is_receiving = true; @@ -202,11 +149,7 @@ void StartReceiving(int port_id) { completion_event_callback, port_id); } -// Cancels any ongoing receiving processes at the specified port. This is used by functions that -// stop capturing. -// TODO: what is the exact behaviour on real 3DS when stopping capture during an ongoing process? -// Will the completion event still be signaled? -void CancelReceiving(int port_id) { +void Module::CancelReceiving(int port_id) { if (!ports[port_id].is_receiving) return; LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process."); @@ -215,8 +158,7 @@ void CancelReceiving(int port_id) { ports[port_id].is_receiving = false; } -// Activates the specified port with the specfied camera. -static void ActivatePort(int port_id, int camera_id) { +void Module::ActivatePort(int port_id, int camera_id) { if (ports[port_id].is_busy && ports[port_id].camera_id != camera_id) { CancelReceiving(port_id); cameras[ports[port_id].camera_id].impl->StopCapture(); @@ -244,27 +186,30 @@ using PortSet = CommandParamBitSet<2>; using ContextSet = CommandParamBitSet<2>; using CameraSet = CommandParamBitSet<3>; -} // namespace +Module::Interface::Interface(std::shared_ptr cam, const char* name, u32 max_session) + : ServiceFramework(name, max_session), cam(std::move(cam)) {} -void StartCapture(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0); +Module::Interface::~Interface() = default; + +void Module::Interface::StartCapture(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x01, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - if (!ports[i].is_busy) { - if (!ports[i].is_active) { + if (!cam->ports[i].is_busy) { + if (!cam->ports[i].is_active) { // This doesn't return an error, but seems to put the camera in an undefined // state LOG_ERROR(Service_CAM, "port %u hasn't been activated", i); } else { - cameras[ports[i].camera_id].impl->StartCapture(); - ports[i].is_busy = true; - if (ports[i].is_pending_receiving) { - ports[i].is_pending_receiving = false; - StartReceiving(i); + cam->cameras[cam->ports[i].camera_id].impl->StartCapture(); + cam->ports[i].is_busy = true; + if (cam->ports[i].is_pending_receiving) { + cam->ports[i].is_pending_receiving = false; + cam->StartReceiving(i); } } } else { @@ -280,18 +225,18 @@ void StartCapture(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } -void StopCapture(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0); +void Module::Interface::StopCapture(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x02, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - if (ports[i].is_busy) { - CancelReceiving(i); - cameras[ports[i].camera_id].impl->StopCapture(); - ports[i].is_busy = false; + if (cam->ports[i].is_busy) { + cam->CancelReceiving(i); + cam->cameras[cam->ports[i].camera_id].impl->StopCapture(); + cam->ports[i].is_busy = false; } else { LOG_WARNING(Service_CAM, "port %u already stopped", i); } @@ -305,8 +250,8 @@ void StopCapture(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } -void IsBusy(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); +void Module::Interface::IsBusy(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x03, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); @@ -315,7 +260,7 @@ void IsBusy(Service::Interface* self) { bool is_busy = true; // Note: the behaviour on no or both ports selected are verified against real 3DS. for (int i : port_select) { - is_busy &= ports[i].is_busy; + is_busy &= cam->ports[i].is_busy; } rb.Push(RESULT_SUCCESS); rb.Push(is_busy); @@ -328,8 +273,8 @@ void IsBusy(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } -void ClearBuffer(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0); +void Module::Interface::ClearBuffer(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x04, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -338,87 +283,86 @@ void ClearBuffer(Service::Interface* self) { LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); } -void GetVsyncInterruptEvent(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0); +void Module::Interface::GetVsyncInterruptEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x05, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); if (port_select.IsSingle()) { int port = *port_select.begin(); rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles( - Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).Unwrap()); + rb.PushCopyObjects(cam->ports[port].vsync_interrupt_event); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE); - rb.PushCopyHandles(0); + rb.PushCopyObjects(nullptr); } LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); } -void GetBufferErrorInterruptEvent(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0); +void Module::Interface::GetBufferErrorInterruptEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x06, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); if (port_select.IsSingle()) { int port = *port_select.begin(); rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles( - Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).Unwrap()); + rb.PushCopyObjects(cam->ports[port].buffer_error_interrupt_event); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE); - rb.PushCopyHandles(0); + rb.PushCopyObjects(nullptr); } LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); } -void SetReceiving(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2); +void Module::Interface::SetReceiving(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x07, 4, 2); const VAddr dest = rp.Pop(); const PortSet port_select(rp.Pop()); const u32 image_size = rp.Pop(); const u16 trans_unit = rp.Pop(); - rp.PopHandle(); // Handle to destination process. not used + auto process = rp.PopObject(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); if (port_select.IsSingle()) { int port_id = *port_select.begin(); - PortConfig& port = ports[port_id]; - CancelReceiving(port_id); + PortConfig& port = cam->ports[port_id]; + cam->CancelReceiving(port_id); port.completion_event->Clear(); + port.dest_process = process.get(); port.dest = dest; port.dest_size = image_size; if (port.is_busy) { - StartReceiving(port_id); + cam->StartReceiving(port_id); } else { port.is_pending_receiving = true; } rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).Unwrap()); + rb.PushCopyObjects(port.completion_event); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE); - rb.PushCopyHandles(0); + rb.PushCopyObjects(nullptr); } LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest, port_select.m_val, image_size, trans_unit); } -void IsFinishedReceiving(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0); +void Module::Interface::IsFinishedReceiving(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x08, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); - bool is_busy = ports[port].is_receiving || ports[port].is_pending_receiving; + bool is_busy = cam->ports[port].is_receiving || cam->ports[port].is_pending_receiving; rb.Push(RESULT_SUCCESS); rb.Push(!is_busy); } else { @@ -430,8 +374,8 @@ void IsFinishedReceiving(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } -void SetTransferLines(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0); +void Module::Interface::SetTransferLines(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x09, 4, 0); const PortSet port_select(rp.Pop()); const u16 transfer_lines = rp.Pop(); const u16 width = rp.Pop(); @@ -440,7 +384,7 @@ void SetTransferLines(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - ports[i].transfer_bytes = transfer_lines * width * 2; + cam->ports[i].transfer_bytes = transfer_lines * width * 2; } rb.Push(RESULT_SUCCESS); } else { @@ -452,8 +396,8 @@ void SetTransferLines(Service::Interface* self) { port_select.m_val, transfer_lines, width, height); } -void GetMaxLines(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0); +void Module::Interface::GetMaxLines(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0A, 2, 0); const u16 width = rp.Pop(); const u16 height = rp.Pop(); @@ -485,8 +429,8 @@ void GetMaxLines(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); } -void SetTransferBytes(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0); +void Module::Interface::SetTransferBytes(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0B, 4, 0); const PortSet port_select(rp.Pop()); const u16 transfer_bytes = rp.Pop(); const u16 width = rp.Pop(); @@ -495,7 +439,7 @@ void SetTransferBytes(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - ports[i].transfer_bytes = transfer_bytes; + cam->ports[i].transfer_bytes = transfer_bytes; } rb.Push(RESULT_SUCCESS); } else { @@ -507,15 +451,15 @@ void SetTransferBytes(Service::Interface* self) { port_select.m_val, transfer_bytes, width, height); } -void GetTransferBytes(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0); +void Module::Interface::GetTransferBytes(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0C, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); rb.Push(RESULT_SUCCESS); - rb.Push(ports[port].transfer_bytes); + rb.Push(cam->ports[port].transfer_bytes); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE); @@ -525,8 +469,8 @@ void GetTransferBytes(Service::Interface* self) { LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val); } -void GetMaxBytes(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0); +void Module::Interface::GetMaxBytes(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0D, 2, 0); const u16 width = rp.Pop(); const u16 height = rp.Pop(); @@ -552,15 +496,15 @@ void GetMaxBytes(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); } -void SetTrimming(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0); +void Module::Interface::SetTrimming(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0E, 2, 0); const PortSet port_select(rp.Pop()); const bool trim = rp.Pop(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - ports[i].is_trimming = trim; + cam->ports[i].is_trimming = trim; } rb.Push(RESULT_SUCCESS); } else { @@ -571,15 +515,15 @@ void SetTrimming(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim); } -void IsTrimming(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0); +void Module::Interface::IsTrimming(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0F, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); rb.Push(RESULT_SUCCESS); - rb.Push(ports[port].is_trimming); + rb.Push(cam->ports[port].is_trimming); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE); @@ -589,8 +533,8 @@ void IsTrimming(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } -void SetTrimmingParams(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0); +void Module::Interface::SetTrimmingParams(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x10, 5, 0); const PortSet port_select(rp.Pop()); const u16 x0 = rp.Pop(); const u16 y0 = rp.Pop(); @@ -600,10 +544,10 @@ void SetTrimmingParams(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - ports[i].x0 = x0; - ports[i].y0 = y0; - ports[i].x1 = x1; - ports[i].y1 = y1; + cam->ports[i].x0 = x0; + cam->ports[i].y0 = y0; + cam->ports[i].x1 = x1; + cam->ports[i].y1 = y1; } rb.Push(RESULT_SUCCESS); } else { @@ -615,18 +559,18 @@ void SetTrimmingParams(Service::Interface* self) { x0, y0, x1, y1); } -void GetTrimmingParams(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0); +void Module::Interface::GetTrimmingParams(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x11, 1, 0); const PortSet port_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); rb.Push(RESULT_SUCCESS); - rb.Push(ports[port].x0); - rb.Push(ports[port].y0); - rb.Push(ports[port].x1); - rb.Push(ports[port].y1); + rb.Push(cam->ports[port].x0); + rb.Push(cam->ports[port].y0); + rb.Push(cam->ports[port].x1); + rb.Push(cam->ports[port].y1); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE); @@ -636,8 +580,8 @@ void GetTrimmingParams(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } -void SetTrimmingParamsCenter(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0); +void Module::Interface::SetTrimmingParamsCenter(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x12, 5, 0); const PortSet port_select(rp.Pop()); const u16 trim_w = rp.Pop(); const u16 trim_h = rp.Pop(); @@ -647,10 +591,10 @@ void SetTrimmingParamsCenter(Service::Interface* self) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { - ports[i].x0 = (cam_w - trim_w) / 2; - ports[i].y0 = (cam_h - trim_h) / 2; - ports[i].x1 = ports[i].x0 + trim_w; - ports[i].y1 = ports[i].y0 + trim_h; + cam->ports[i].x0 = (cam_w - trim_w) / 2; + cam->ports[i].y0 = (cam_h - trim_h) / 2; + cam->ports[i].x1 = cam->ports[i].x0 + trim_w; + cam->ports[i].y1 = cam->ports[i].y0 + trim_h; } rb.Push(RESULT_SUCCESS); } else { @@ -662,20 +606,20 @@ void SetTrimmingParamsCenter(Service::Interface* self) { port_select.m_val, trim_w, trim_h, cam_w, cam_h); } -void Activate(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0); +void Module::Interface::Activate(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x13, 1, 0); const CameraSet camera_select(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid()) { if (camera_select.m_val == 0) { // deactive all for (int i = 0; i < 2; ++i) { - if (ports[i].is_busy) { - CancelReceiving(i); - cameras[ports[i].camera_id].impl->StopCapture(); - ports[i].is_busy = false; + if (cam->ports[i].is_busy) { + cam->CancelReceiving(i); + cam->cameras[cam->ports[i].camera_id].impl->StopCapture(); + cam->ports[i].is_busy = false; } - ports[i].is_active = false; + cam->ports[i].is_active = false; } rb.Push(RESULT_SUCCESS); } else if (camera_select[0] && camera_select[1]) { @@ -683,13 +627,13 @@ void Activate(Service::Interface* self) { rb.Push(ERROR_INVALID_ENUM_VALUE); } else { if (camera_select[0]) { - ActivatePort(0, 0); + cam->ActivatePort(0, 0); } else if (camera_select[1]) { - ActivatePort(0, 1); + cam->ActivatePort(0, 1); } if (camera_select[2]) { - ActivatePort(1, 2); + cam->ActivatePort(1, 2); } rb.Push(RESULT_SUCCESS); } @@ -701,8 +645,8 @@ void Activate(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val); } -void SwitchContext(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0); +void Module::Interface::SwitchContext(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x14, 2, 0); const CameraSet camera_select(rp.Pop()); const ContextSet context_select(rp.Pop()); @@ -710,12 +654,12 @@ void SwitchContext(Service::Interface* self) { if (camera_select.IsValid() && context_select.IsSingle()) { int context = *context_select.begin(); for (int camera : camera_select) { - cameras[camera].current_context = context; - const ContextConfig& context_config = cameras[camera].contexts[context]; - cameras[camera].impl->SetFlip(context_config.flip); - cameras[camera].impl->SetEffect(context_config.effect); - cameras[camera].impl->SetFormat(context_config.format); - cameras[camera].impl->SetResolution(context_config.resolution); + cam->cameras[camera].current_context = context; + const ContextConfig& context_config = cam->cameras[camera].contexts[context]; + cam->cameras[camera].impl->SetFlip(context_config.flip); + cam->cameras[camera].impl->SetEffect(context_config.effect); + cam->cameras[camera].impl->SetFormat(context_config.format); + cam->cameras[camera].impl->SetResolution(context_config.resolution); } rb.Push(RESULT_SUCCESS); } else { @@ -728,8 +672,8 @@ void SwitchContext(Service::Interface* self) { context_select.m_val); } -void FlipImage(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0); +void Module::Interface::FlipImage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1D, 3, 0); const CameraSet camera_select(rp.Pop()); const Flip flip = static_cast(rp.Pop()); const ContextSet context_select(rp.Pop()); @@ -738,9 +682,9 @@ void FlipImage(Service::Interface* self) { if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { - cameras[camera].contexts[context].flip = flip; - if (cameras[camera].current_context == context) { - cameras[camera].impl->SetFlip(flip); + cam->cameras[camera].contexts[context].flip = flip; + if (cam->cameras[camera].current_context == context) { + cam->cameras[camera].impl->SetFlip(flip); } } } @@ -755,8 +699,8 @@ void FlipImage(Service::Interface* self) { camera_select.m_val, static_cast(flip), context_select.m_val); } -void SetDetailSize(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0); +void Module::Interface::SetDetailSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1E, 8, 0); const CameraSet camera_select(rp.Pop()); Resolution resolution; resolution.width = rp.Pop(); @@ -771,9 +715,9 @@ void SetDetailSize(Service::Interface* self) { if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { - cameras[camera].contexts[context].resolution = resolution; - if (cameras[camera].current_context == context) { - cameras[camera].impl->SetResolution(resolution); + cam->cameras[camera].contexts[context].resolution = resolution; + if (cam->cameras[camera].current_context == context) { + cam->cameras[camera].impl->SetResolution(resolution); } } } @@ -790,8 +734,8 @@ void SetDetailSize(Service::Interface* self) { resolution.crop_y0, resolution.crop_x1, resolution.crop_y1, context_select.m_val); } -void SetSize(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0); +void Module::Interface::SetSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1F, 3, 0); const CameraSet camera_select(rp.Pop()); const u8 size = rp.Pop(); const ContextSet context_select(rp.Pop()); @@ -800,9 +744,9 @@ void SetSize(Service::Interface* self) { if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { - cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size]; - if (cameras[camera].current_context == context) { - cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]); + cam->cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size]; + if (cam->cameras[camera].current_context == context) { + cam->cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]); } } } @@ -817,15 +761,15 @@ void SetSize(Service::Interface* self) { camera_select.m_val, size, context_select.m_val); } -void SetFrameRate(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0); +void Module::Interface::SetFrameRate(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x20, 2, 0); const CameraSet camera_select(rp.Pop()); const FrameRate frame_rate = static_cast(rp.Pop()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid()) { for (int camera : camera_select) { - cameras[camera].frame_rate = frame_rate; + cam->cameras[camera].frame_rate = frame_rate; // TODO(wwylele): consider hinting the actual camera with the expected frame rate } rb.Push(RESULT_SUCCESS); @@ -838,8 +782,8 @@ void SetFrameRate(Service::Interface* self) { camera_select.m_val, static_cast(frame_rate)); } -void SetEffect(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0); +void Module::Interface::SetEffect(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x22, 3, 0); const CameraSet camera_select(rp.Pop()); const Effect effect = static_cast(rp.Pop()); const ContextSet context_select(rp.Pop()); @@ -848,9 +792,9 @@ void SetEffect(Service::Interface* self) { if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { - cameras[camera].contexts[context].effect = effect; - if (cameras[camera].current_context == context) { - cameras[camera].impl->SetEffect(effect); + cam->cameras[camera].contexts[context].effect = effect; + if (cam->cameras[camera].current_context == context) { + cam->cameras[camera].impl->SetEffect(effect); } } } @@ -865,8 +809,8 @@ void SetEffect(Service::Interface* self) { camera_select.m_val, static_cast(effect), context_select.m_val); } -void SetOutputFormat(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0); +void Module::Interface::SetOutputFormat(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x25, 3, 0); const CameraSet camera_select(rp.Pop()); const OutputFormat format = static_cast(rp.Pop()); const ContextSet context_select(rp.Pop()); @@ -875,9 +819,9 @@ void SetOutputFormat(Service::Interface* self) { if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { - cameras[camera].contexts[context].format = format; - if (cameras[camera].current_context == context) { - cameras[camera].impl->SetFormat(format); + cam->cameras[camera].contexts[context].format = format; + if (cam->cameras[camera].current_context == context) { + cam->cameras[camera].impl->SetFormat(format); } } } @@ -892,8 +836,8 @@ void SetOutputFormat(Service::Interface* self) { camera_select.m_val, static_cast(format), context_select.m_val); } -void SynchronizeVsyncTiming(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0); +void Module::Interface::SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x29, 2, 0); const u8 camera_select1 = rp.Pop(); const u8 camera_select2 = rp.Pop(); @@ -904,9 +848,8 @@ void SynchronizeVsyncTiming(Service::Interface* self) { camera_select1, camera_select2); } -void GetStereoCameraCalibrationData(Service::Interface* self) { - IPC::RequestBuilder rb = - IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0); +void Module::Interface::GetStereoCameraCalibrationData(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb = IPC::RequestParser(ctx, 0x2B, 0, 0).MakeBuilder(17, 0); // Default values taken from yuriks' 3DS. Valid data is required here or games using the // calibration get stuck in an infinite CPU loop. @@ -931,8 +874,8 @@ void GetStereoCameraCalibrationData(Service::Interface* self) { LOG_TRACE(Service_CAM, "called"); } -void SetPackageParameterWithoutContext(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0); +void Module::Interface::SetPackageParameterWithoutContext(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x33, 11, 0); PackageParameterWithoutContext package; rp.PopRaw(package); @@ -944,7 +887,7 @@ void SetPackageParameterWithoutContext(Service::Interface* self) { } template -static ResultCode SetPackageParameter(const PackageParameterType& package) { +ResultCode Module::SetPackageParameter(const PackageParameterType& package) { const CameraSet camera_select(package.camera_select); const ContextSet context_select(package.context_select); @@ -975,34 +918,34 @@ Resolution PackageParameterWithContext::GetResolution() const { return PRESET_RESOLUTION[static_cast(size)]; } -void SetPackageParameterWithContext(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0); +void Module::Interface::SetPackageParameterWithContext(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x34, 5, 0); PackageParameterWithContext package; rp.PopRaw(package); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - ResultCode result = SetPackageParameter(package); + ResultCode result = cam->SetPackageParameter(package); rb.Push(result); LOG_DEBUG(Service_CAM, "called"); } -void SetPackageParameterWithContextDetail(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0); +void Module::Interface::SetPackageParameterWithContextDetail(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x35, 7, 0); PackageParameterWithContextDetail package; rp.PopRaw(package); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - ResultCode result = SetPackageParameter(package); + ResultCode result = cam->SetPackageParameter(package); rb.Push(result); LOG_DEBUG(Service_CAM, "called"); } -void GetSuitableY2rStandardCoefficient(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0); +void Module::Interface::GetSuitableY2rStandardCoefficient(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x36, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(0); @@ -1010,8 +953,8 @@ void GetSuitableY2rStandardCoefficient(Service::Interface* self) { LOG_WARNING(Service_CAM, "(STUBBED) called"); } -void PlayShutterSound(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0); +void Module::Interface::PlayShutterSound(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x38, 1, 0); u8 sound_id = rp.Pop(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -1020,12 +963,12 @@ void PlayShutterSound(Service::Interface* self) { LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); } -void DriverInitialize(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0); +void Module::Interface::DriverInitialize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x39, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); for (int camera_id = 0; camera_id < NumCameras; ++camera_id) { - CameraConfig& camera = cameras[camera_id]; + CameraConfig& camera = cam->cameras[camera_id]; camera.current_context = 0; for (int context_id = 0; context_id < 2; ++context_id) { // Note: the following default values are verified against real 3DS @@ -1044,7 +987,7 @@ void DriverInitialize(Service::Interface* self) { camera.impl->SetResolution(camera.contexts[0].resolution); } - for (PortConfig& port : ports) { + for (PortConfig& port : cam->ports) { port.Clear(); } @@ -1053,14 +996,14 @@ void DriverInitialize(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called"); } -void DriverFinalize(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0); +void Module::Interface::DriverFinalize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x3A, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - CancelReceiving(0); - CancelReceiving(1); + cam->CancelReceiving(0); + cam->CancelReceiving(1); - for (CameraConfig& camera : cameras) { + for (CameraConfig& camera : cam->cameras) { camera.impl = nullptr; } @@ -1069,36 +1012,31 @@ void DriverFinalize(Service::Interface* self) { LOG_DEBUG(Service_CAM, "called"); } -void Init() { +Module::Module() { using namespace Kernel; - - AddService(new CAM_C_Interface); - AddService(new CAM_Q_Interface); - AddService(new CAM_S_Interface); - AddService(new CAM_U_Interface); - for (PortConfig& port : ports) { - port.completion_event = Event::Create(ResetType::Sticky, "CAM_U::completion_event"); + port.completion_event = Event::Create(ResetType::Sticky, "CAM::completion_event"); port.buffer_error_interrupt_event = - Event::Create(ResetType::OneShot, "CAM_U::buffer_error_interrupt_event"); + Event::Create(ResetType::OneShot, "CAM::buffer_error_interrupt_event"); port.vsync_interrupt_event = - Event::Create(ResetType::OneShot, "CAM_U::vsync_interrupt_event"); + Event::Create(ResetType::OneShot, "CAM::vsync_interrupt_event"); } - completion_event_callback = - CoreTiming::RegisterEvent("CAM_U::CompletionEventCallBack", CompletionEventCallBack); + completion_event_callback = CoreTiming::RegisterEvent( + "CAM::CompletionEventCallBack", + [this](u64 userdata, int cycles_late) { CompletionEventCallBack(userdata, cycles_late); }); } -void Shutdown() { +Module::~Module() { CancelReceiving(0); CancelReceiving(1); - for (PortConfig& port : ports) { - port.completion_event = nullptr; - port.buffer_error_interrupt_event = nullptr; - port.vsync_interrupt_event = nullptr; - } - for (CameraConfig& camera : cameras) { - camera.impl = nullptr; - } +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + auto cam = std::make_shared(); + std::make_shared(cam)->InstallAsService(service_manager); + std::make_shared(cam)->InstallAsService(service_manager); + std::make_shared(cam)->InstallAsService(service_manager); + std::make_shared()->InstallAsService(service_manager); } } // namespace CAM diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h index b6da721d8..c1c13eae6 100644 --- a/src/core/hle/service/cam/cam.h +++ b/src/core/hle/service/cam/cam.h @@ -4,12 +4,27 @@ #pragma once -#include "common/common_funcs.h" +#include +#include +#include +#include #include "common/common_types.h" #include "common/swap.h" -#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" #include "core/hle/service/service.h" +namespace Camera { +class CameraInterface; +} + +namespace CoreTiming { +class EventType; +} + +namespace Kernel { +class Process; +} + namespace Service { namespace CAM { @@ -221,466 +236,547 @@ struct PackageParameterWithContextDetail { static_assert(sizeof(PackageParameterWithContextDetail) == 28, "PackageParameterWithContextDetail structure size is wrong"); -/** - * Starts capturing at the selected port. - * Inputs: - * 0: 0x00010040 - * 1: u8 selected port - * Outputs: - * 0: 0x00010040 - * 1: ResultCode - */ -void StartCapture(Service::Interface* self); +class Module final { +public: + Module(); + ~Module(); -/** - * Stops capturing from the selected port. - * Inputs: - * 0: 0x00020040 - * 1: u8 selected port - * Outputs: - * 0: 0x00020040 - * 1: ResultCode - */ -void StopCapture(Service::Interface* self); + class Interface : public ServiceFramework { + public: + Interface(std::shared_ptr cam, const char* name, u32 max_session); + ~Interface(); -/** - * Gets whether the selected port is currently capturing. - * Inputs: - * 0: 0x00030040 - * 1: u8 selected port - * Outputs: - * 0: 0x00030080 - * 1: ResultCode - * 2: 0 if not capturing, 1 if capturing - */ -void IsBusy(Service::Interface* self); + protected: + /** + * Starts capturing at the selected port. + * Inputs: + * 0: 0x00010040 + * 1: u8 selected port + * Outputs: + * 0: 0x00010040 + * 1: ResultCode + */ + void StartCapture(Kernel::HLERequestContext& ctx); -/** - * Clears the buffer of selected ports. - * Inputs: - * 0: 0x00040040 - * 1: u8 selected port - * Outputs: - * 0: 0x00040040 - * 2: ResultCode - */ -void ClearBuffer(Service::Interface* self); + /** + * Stops capturing from the selected port. + * Inputs: + * 0: 0x00020040 + * 1: u8 selected port + * Outputs: + * 0: 0x00020040 + * 1: ResultCode + */ + void StopCapture(Kernel::HLERequestContext& ctx); -/** - * Unknown - * Inputs: - * 0: 0x00050040 - * 1: u8 selected port - * Outputs: - * 0: 0x00050042 - * 1: ResultCode - * 2: Descriptor: Handle - * 3: Event handle - */ -void GetVsyncInterruptEvent(Service::Interface* self); + /** + * Gets whether the selected port is currently capturing. + * Inputs: + * 0: 0x00030040 + * 1: u8 selected port + * Outputs: + * 0: 0x00030080 + * 1: ResultCode + * 2: 0 if not capturing, 1 if capturing + */ + void IsBusy(Kernel::HLERequestContext& ctx); -/** - * Unknown - * Inputs: - * 0: 0x00060040 - * 1: u8 selected port - * Outputs: - * 0: 0x00060042 - * 1: ResultCode - * 2: Descriptor: Handle - * 3: Event handle - */ -void GetBufferErrorInterruptEvent(Service::Interface* self); + /** + * Clears the buffer of selected ports. + * Inputs: + * 0: 0x00040040 + * 1: u8 selected port + * Outputs: + * 0: 0x00040040 + * 2: ResultCode + */ + void ClearBuffer(Kernel::HLERequestContext& ctx); -/** - * 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 selected port - * 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: 0x00050040 + * 1: u8 selected port + * Outputs: + * 0: 0x00050042 + * 1: ResultCode + * 2: Descriptor: Handle + * 3: Event handle + */ + void GetVsyncInterruptEvent(Kernel::HLERequestContext& ctx); -/** - * Gets whether the selected port finished receiving a frame. - * Inputs: - * 0: 0x00080040 - * 1: u8 selected port - * Outputs: - * 0: 0x00080080 - * 1: ResultCode - * 2: 0 if not finished, 1 if finished - */ -void IsFinishedReceiving(Service::Interface* self); + /** + * Unknown + * Inputs: + * 0: 0x00060040 + * 1: u8 selected port + * Outputs: + * 0: 0x00060042 + * 1: ResultCode + * 2: Descriptor: Handle + * 3: Event handle + */ + void GetBufferErrorInterruptEvent(Kernel::HLERequestContext& ctx); -/** - * Sets the number of lines the buffer contains. - * Inputs: - * 0: 0x00090100 - * 1: u8 selected port - * 2: u16 Number of lines to transfer - * 3: u16 Width - * 4: u16 Height - * Outputs: - * 0: 0x00090040 - * 1: ResultCode - * @todo figure out how the "buffer" actually works. - */ -void SetTransferLines(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 selected port + * 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(Kernel::HLERequestContext& ctx); -/** - * Gets the maximum number of lines that fit in the buffer - * Inputs: - * 0: 0x000A0080 - * 1: u16 Width - * 2: u16 Height - * Outputs: - * 0: 0x000A0080 - * 1: ResultCode - * 2: Maximum number of lines that fit in the buffer - * @todo figure out how the "buffer" actually works. - */ -void GetMaxLines(Service::Interface* self); + /** + * Gets whether the selected port finished receiving a frame. + * Inputs: + * 0: 0x00080040 + * 1: u8 selected port + * Outputs: + * 0: 0x00080080 + * 1: ResultCode + * 2: 0 if not finished, 1 if finished + */ + void IsFinishedReceiving(Kernel::HLERequestContext& ctx); -/** - * Sets the number of bytes the buffer contains. - * Inputs: - * 0: 0x000B0100 - * 1: u8 selected port - * 2: u16 Number of bytes to transfer - * 3: u16 Width - * 4: u16 Height - * Outputs: - * 0: 0x000B0040 - * 1: ResultCode - * @todo figure out how the "buffer" actually works. - */ -void SetTransferBytes(Service::Interface* self); + /** + * Sets the number of lines the buffer contains. + * Inputs: + * 0: 0x00090100 + * 1: u8 selected port + * 2: u16 Number of lines to transfer + * 3: u16 Width + * 4: u16 Height + * Outputs: + * 0: 0x00090040 + * 1: ResultCode + * @todo figure out how the "buffer" actually works. + */ + void SetTransferLines(Kernel::HLERequestContext& ctx); -/** - * Gets the number of bytes to the buffer contains. - * Inputs: - * 0: 0x000C0040 - * 1: u8 selected port - * Outputs: - * 0: 0x000C0080 - * 1: ResultCode - * 2: The number of bytes the buffer contains - * @todo figure out how the "buffer" actually works. - */ -void GetTransferBytes(Service::Interface* self); + /** + * Gets the maximum number of lines that fit in the buffer + * Inputs: + * 0: 0x000A0080 + * 1: u16 Width + * 2: u16 Height + * Outputs: + * 0: 0x000A0080 + * 1: ResultCode + * 2: Maximum number of lines that fit in the buffer + * @todo figure out how the "buffer" actually works. + */ + void GetMaxLines(Kernel::HLERequestContext& ctx); -/** - * Gets the maximum number of bytes that fit in the buffer. - * Inputs: - * 0: 0x000D0080 - * 1: u16 Width - * 2: u16 Height - * Outputs: - * 0: 0x000D0080 - * 1: ResultCode - * 2: Maximum number of bytes that fit in the buffer - * @todo figure out how the "buffer" actually works. - */ -void GetMaxBytes(Service::Interface* self); + /** + * Sets the number of bytes the buffer contains. + * Inputs: + * 0: 0x000B0100 + * 1: u8 selected port + * 2: u16 Number of bytes to transfer + * 3: u16 Width + * 4: u16 Height + * Outputs: + * 0: 0x000B0040 + * 1: ResultCode + * @todo figure out how the "buffer" actually works. + */ + void SetTransferBytes(Kernel::HLERequestContext& ctx); -/** - * Enables or disables trimming. - * Inputs: - * 0: 0x000E0080 - * 1: u8 selected port - * 2: u8 bool Enable trimming if true - * Outputs: - * 0: 0x000E0040 - * 1: ResultCode - */ -void SetTrimming(Service::Interface* self); + /** + * Gets the number of bytes to the buffer contains. + * Inputs: + * 0: 0x000C0040 + * 1: u8 selected port + * Outputs: + * 0: 0x000C0080 + * 1: ResultCode + * 2: The number of bytes the buffer contains + * @todo figure out how the "buffer" actually works. + */ + void GetTransferBytes(Kernel::HLERequestContext& ctx); -/** - * Gets whether trimming is enabled. - * Inputs: - * 0: 0x000F0040 - * 1: u8 selected port - * Outputs: - * 0: 0x000F0080 - * 1: ResultCode - * 2: u8 bool Enable trimming if true - */ -void IsTrimming(Service::Interface* self); + /** + * Gets the maximum number of bytes that fit in the buffer. + * Inputs: + * 0: 0x000D0080 + * 1: u16 Width + * 2: u16 Height + * Outputs: + * 0: 0x000D0080 + * 1: ResultCode + * 2: Maximum number of bytes that fit in the buffer + * @todo figure out how the "buffer" actually works. + */ + void GetMaxBytes(Kernel::HLERequestContext& ctx); -/** - * Sets the position to trim. - * Inputs: - * 0: 0x00100140 - * 1: u8 selected port - * 2: x start - * 3: y start - * 4: x end (exclusive) - * 5: y end (exclusive) - * Outputs: - * 0: 0x00100040 - * 1: ResultCode - */ -void SetTrimmingParams(Service::Interface* self); + /** + * Enables or disables trimming. + * Inputs: + * 0: 0x000E0080 + * 1: u8 selected port + * 2: u8 bool Enable trimming if true + * Outputs: + * 0: 0x000E0040 + * 1: ResultCode + */ + void SetTrimming(Kernel::HLERequestContext& ctx); -/** - * Gets the position to trim. - * Inputs: - * 0: 0x00110040 - * 1: u8 selected port - * - * Outputs: - * 0: 0x00110140 - * 1: ResultCode - * 2: x start - * 3: y start - * 4: x end (exclusive) - * 5: y end (exclusive) - */ -void GetTrimmingParams(Service::Interface* self); + /** + * Gets whether trimming is enabled. + * Inputs: + * 0: 0x000F0040 + * 1: u8 selected port + * Outputs: + * 0: 0x000F0080 + * 1: ResultCode + * 2: u8 bool Enable trimming if true + */ + void IsTrimming(Kernel::HLERequestContext& ctx); -/** - * Sets the position to trim by giving the width and height. The trimming window is always at the - * center. - * Inputs: - * 0: 0x00120140 - * 1: u8 selected port - * 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); + /** + * Sets the position to trim. + * Inputs: + * 0: 0x00100140 + * 1: u8 selected port + * 2: x start + * 3: y start + * 4: x end (exclusive) + * 5: y end (exclusive) + * Outputs: + * 0: 0x00100040 + * 1: ResultCode + */ + void SetTrimmingParams(Kernel::HLERequestContext& ctx); -/** - * Selects up to two physical cameras to enable. - * Inputs: - * 0: 0x00130040 - * 1: u8 selected camera - * Outputs: - * 0: 0x00130040 - * 1: ResultCode - */ -void Activate(Service::Interface* self); + /** + * Gets the position to trim. + * Inputs: + * 0: 0x00110040 + * 1: u8 selected port + * + * Outputs: + * 0: 0x00110140 + * 1: ResultCode + * 2: x start + * 3: y start + * 4: x end (exclusive) + * 5: y end (exclusive) + */ + void GetTrimmingParams(Kernel::HLERequestContext& ctx); -/** - * Switches the context of camera settings. - * Inputs: - * 0: 0x00140080 - * 1: u8 selected camera - * 2: u8 selected context - * Outputs: - * 0: 0x00140040 - * 1: ResultCode - */ -void SwitchContext(Service::Interface* self); + /** + * Sets the position to trim by giving the width and height. The trimming window is always + * at the center. + * Inputs: + * 0: 0x00120140 + * 1: u8 selected port + * 2: s16 Trim width + * 3: s16 Trim height + * 4: s16 Camera width + * 5: s16 Camera height + * Outputs: + * 0: 0x00120040 + * 1: ResultCode + */ + void SetTrimmingParamsCenter(Kernel::HLERequestContext& ctx); -/** - * Sets flipping of images - * Inputs: - * 0: 0x001D00C0 - * 1: u8 selected camera - * 2: u8 Type of flipping to perform (`Flip` enum) - * 3: u8 selected context - * Outputs: - * 0: 0x001D0040 - * 1: ResultCode - */ -void FlipImage(Service::Interface* self); + /** + * Selects up to two physical cameras to enable. + * Inputs: + * 0: 0x00130040 + * 1: u8 selected camera + * Outputs: + * 0: 0x00130040 + * 1: ResultCode + */ + void Activate(Kernel::HLERequestContext& ctx); -/** - * Sets camera resolution from custom parameters. For more details see the Resolution struct. - * Inputs: - * 0: 0x001E0200 - * 1: u8 selected camera - * 2: width - * 3: height - * 4: crop x0 - * 5: crop y0 - * 6: crop x1 - * 7: crop y1 - * 8: u8 selected context - * Outputs: - * 0: 0x001E0040 - * 1: ResultCode - */ -void SetDetailSize(Service::Interface* self); + /** + * Switches the context of camera settings. + * Inputs: + * 0: 0x00140080 + * 1: u8 selected camera + * 2: u8 selected context + * Outputs: + * 0: 0x00140040 + * 1: ResultCode + */ + void SwitchContext(Kernel::HLERequestContext& ctx); -/** - * Sets camera resolution from preset resolution parameters. - * Inputs: - * 0: 0x001F00C0 - * 1: u8 selected camera - * 2: u8 Camera frame resolution (`Size` enum) - * 3: u8 selected context - * Outputs: - * 0: 0x001F0040 - * 1: ResultCode - */ -void SetSize(Service::Interface* self); + /** + * Sets flipping of images + * Inputs: + * 0: 0x001D00C0 + * 1: u8 selected camera + * 2: u8 Type of flipping to perform (`Flip` enum) + * 3: u8 selected context + * Outputs: + * 0: 0x001D0040 + * 1: ResultCode + */ + void FlipImage(Kernel::HLERequestContext& ctx); -/** - * Sets camera framerate. - * Inputs: - * 0: 0x00200080 - * 1: u8 selected camera - * 2: u8 Camera framerate (`FrameRate` enum) - * Outputs: - * 0: 0x00200040 - * 1: ResultCode - */ -void SetFrameRate(Service::Interface* self); + /** + * Sets camera resolution from custom parameters. For more details see the Resolution + * struct. + * Inputs: + * 0: 0x001E0200 + * 1: u8 selected camera + * 2: width + * 3: height + * 4: crop x0 + * 5: crop y0 + * 6: crop x1 + * 7: crop y1 + * 8: u8 selected context + * Outputs: + * 0: 0x001E0040 + * 1: ResultCode + */ + void SetDetailSize(Kernel::HLERequestContext& ctx); -/** - * Sets effect on the output image - * Inputs: - * 0: 0x002200C0 - * 1: u8 selected camera - * 2: u8 image effect (`Effect` enum) - * 3: u8 selected context - * Outputs: - * 0: 0x00220040 - * 1: ResultCode - */ -void SetEffect(Service::Interface* self); + /** + * Sets camera resolution from preset resolution parameters. + * Inputs: + * 0: 0x001F00C0 + * 1: u8 selected camera + * 2: u8 Camera frame resolution (`Size` enum) + * 3: u8 selected context + * Outputs: + * 0: 0x001F0040 + * 1: ResultCode + */ + void SetSize(Kernel::HLERequestContext& ctx); -/** - * Sets format of the output image - * Inputs: - * 0: 0x002500C0 - * 1: u8 selected camera - * 2: u8 image format (`OutputFormat` enum) - * 3: u8 selected context - * Outputs: - * 0: 0x00250040 - * 1: ResultCode - */ -void SetOutputFormat(Service::Interface* self); + /** + * Sets camera framerate. + * Inputs: + * 0: 0x00200080 + * 1: u8 selected camera + * 2: u8 Camera framerate (`FrameRate` enum) + * Outputs: + * 0: 0x00200040 + * 1: ResultCode + */ + void SetFrameRate(Kernel::HLERequestContext& ctx); -/** - * Synchronizes the V-Sync timing of two cameras. - * Inputs: - * 0: 0x00290080 - * 1: u8 selected camera 1 - * 2: u8 selected camera 2 - * Outputs: - * 0: 0x00280040 - * 1: ResultCode - */ -void SynchronizeVsyncTiming(Service::Interface* self); + /** + * Sets effect on the output image + * Inputs: + * 0: 0x002200C0 + * 1: u8 selected camera + * 2: u8 image effect (`Effect` enum) + * 3: u8 selected context + * Outputs: + * 0: 0x00220040 + * 1: ResultCode + */ + void SetEffect(Kernel::HLERequestContext& ctx); -/** - * 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); + /** + * Sets format of the output image + * Inputs: + * 0: 0x002500C0 + * 1: u8 selected camera + * 2: u8 image format (`OutputFormat` enum) + * 3: u8 selected context + * Outputs: + * 0: 0x00250040 + * 1: ResultCode + */ + void SetOutputFormat(Kernel::HLERequestContext& ctx); -/** - * Batch-configures context-free settings. - * - * Inputs: - * 0: 0x003302C0 - * 1-7: struct PachageParameterWithoutContext - * 8-11: unused - * Outputs: - * 0: 0x00330040 - * 1: ResultCode - */ -void SetPackageParameterWithoutContext(Service::Interface* self); + /** + * Synchronizes the V-Sync timing of two cameras. + * Inputs: + * 0: 0x00290080 + * 1: u8 selected camera 1 + * 2: u8 selected camera 2 + * Outputs: + * 0: 0x00280040 + * 1: ResultCode + */ + void SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx); -/** - * Batch-configures context-related settings with preset resolution parameters. - * - * Inputs: - * 0: 0x00340140 - * 1-2: struct PackageParameterWithContext - * 3-5: unused - * Outputs: - * 0: 0x00340040 - * 1: ResultCode - */ -void SetPackageParameterWithContext(Service::Interface* self); + /** + * Returns calibration data relating the outside cameras to each other, for use in AR + * applications. + * + * Inputs: + * 0: 0x002B0000 + * Outputs: + * 0: 0x002B0440 + * 1: ResultCode + * 2-17: `StereoCameraCalibrationData` structure with calibration values + */ + void GetStereoCameraCalibrationData(Kernel::HLERequestContext& ctx); -/** - * Batch-configures context-related settings with custom resolution parameters - * - * Inputs: - * 0: 0x003501C0 - * 1-4: struct PackageParameterWithContextDetail - * 5-7: unused - * Outputs: - * 0: 0x00350040 - * 1: ResultCode - */ -void SetPackageParameterWithContextDetail(Service::Interface* self); + /** + * Batch-configures context-free settings. + * + * Inputs: + * 0: 0x003302C0 + * 1-7: struct PachageParameterWithoutContext + * 8-11: unused + * Outputs: + * 0: 0x00330040 + * 1: ResultCode + */ + void SetPackageParameterWithoutContext(Kernel::HLERequestContext& ctx); -/** - * Unknown - * Inputs: - * 0: 0x00360000 - * Outputs: - * 0: 0x00360080 - * 1: ResultCode - * 2: ? - */ -void GetSuitableY2rStandardCoefficient(Service::Interface* self); + /** + * Batch-configures context-related settings with preset resolution parameters. + * + * Inputs: + * 0: 0x00340140 + * 1-2: struct PackageParameterWithContext + * 3-5: unused + * Outputs: + * 0: 0x00340040 + * 1: ResultCode + */ + void SetPackageParameterWithContext(Kernel::HLERequestContext& ctx); -/** - * Unknown - * Inputs: - * 0: 0x00380040 - * 1: u8 Sound ID - * Outputs: - * 0: 0x00380040 - * 1: ResultCode - */ -void PlayShutterSound(Service::Interface* self); + /** + * Batch-configures context-related settings with custom resolution parameters + * + * Inputs: + * 0: 0x003501C0 + * 1-4: struct PackageParameterWithContextDetail + * 5-7: unused + * Outputs: + * 0: 0x00350040 + * 1: ResultCode + */ + void SetPackageParameterWithContextDetail(Kernel::HLERequestContext& ctx); -/** - * Initializes the camera driver. Must be called before using other functions. - * Inputs: - * 0: 0x00390000 - * Outputs: - * 0: 0x00390040 - * 1: ResultCode - */ -void DriverInitialize(Service::Interface* self); + /** + * Unknown + * Inputs: + * 0: 0x00360000 + * Outputs: + * 0: 0x00360080 + * 1: ResultCode + * 2: ? + */ + void GetSuitableY2rStandardCoefficient(Kernel::HLERequestContext& ctx); -/** - * Shuts down the camera driver. - * Inputs: - * 0: 0x003A0000 - * Outputs: - * 0: 0x003A0040 - * 1: ResultCode - */ -void DriverFinalize(Service::Interface* self); + /** + * Unknown + * Inputs: + * 0: 0x00380040 + * 1: u8 Sound ID + * Outputs: + * 0: 0x00380040 + * 1: ResultCode + */ + void PlayShutterSound(Kernel::HLERequestContext& ctx); -/// Initialize CAM service(s) -void Init(); + /** + * Initializes the camera driver. Must be called before using other functions. + * Inputs: + * 0: 0x00390000 + * Outputs: + * 0: 0x00390040 + * 1: ResultCode + */ + void DriverInitialize(Kernel::HLERequestContext& ctx); -/// Shutdown CAM service(s) -void Shutdown(); + /** + * Shuts down the camera driver. + * Inputs: + * 0: 0x003A0000 + * Outputs: + * 0: 0x003A0040 + * 1: ResultCode + */ + void DriverFinalize(Kernel::HLERequestContext& ctx); + + private: + std::shared_ptr cam; + }; + +private: + void CompletionEventCallBack(u64 port_id, int); + + // Starts a receiving process on the specified port. This can only be called when is_busy = true + // and is_receiving = false. + void StartReceiving(int port_id); + + // Cancels any ongoing receiving processes at the specified port. This is used by functions that + // stop capturing. + // TODO: what is the exact behaviour on real 3DS when stopping capture during an ongoing + // process? Will the completion event still be signaled? + void CancelReceiving(int port_id); + + // Activates the specified port with the specfied camera. + void ActivatePort(int port_id, int camera_id); + + template + ResultCode SetPackageParameter(const PackageParameterType& package); + + struct ContextConfig { + Flip flip; + Effect effect; + OutputFormat format; + Resolution resolution; + }; + + struct CameraConfig { + std::unique_ptr impl; + std::array contexts; + int current_context; + FrameRate frame_rate; + }; + + struct PortConfig { + int camera_id; + + bool is_active; // set when the port is activated by an Activate call. + bool is_pending_receiving; // set if SetReceiving is called when is_busy = false. When + // StartCapture is called then, this will trigger a receiving + // process and reset itself. + bool is_busy; // set when StartCapture is called and reset when StopCapture is called. + bool is_receiving; // set when there is an ongoing receiving process. + + bool is_trimming; + u16 x0; // x-coordinate of starting position for trimming + u16 y0; // y-coordinate of starting position for trimming + u16 x1; // x-coordinate of ending position for trimming + u16 y1; // y-coordinate of ending position for trimming + + u16 transfer_bytes; + + Kernel::SharedPtr completion_event; + Kernel::SharedPtr buffer_error_interrupt_event; + Kernel::SharedPtr vsync_interrupt_event; + + std::future> capture_result; // will hold the received frame. + Kernel::Process* dest_process; + VAddr dest; // the destination address of the receiving process + u32 dest_size; // the destination size of the receiving process + + void Clear(); + }; + + std::array cameras; + std::array ports; + CoreTiming::EventType* completion_event_callback; +}; + +void InstallInterfaces(SM::ServiceManager& service_manager); } // namespace CAM } // namespace Service diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp index 93b047c1a..db46413cc 100644 --- a/src/core/hle/service/cam/cam_c.cpp +++ b/src/core/hle/service/cam/cam_c.cpp @@ -2,16 +2,81 @@ // 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_c.h" namespace Service { namespace CAM { -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -CAM_C_Interface::CAM_C_Interface() { - // Register(FunctionTable); +CAM_C::CAM_C(std::shared_ptr cam) : Module::Interface(std::move(cam), "cam:c", 1) { + static const FunctionInfo functions[] = { + {0x00010040, &CAM_C::StartCapture, "StartCapture"}, + {0x00020040, &CAM_C::StopCapture, "StopCapture"}, + {0x00030040, &CAM_C::IsBusy, "IsBusy"}, + {0x00040040, &CAM_C::ClearBuffer, "ClearBuffer"}, + {0x00050040, &CAM_C::GetVsyncInterruptEvent, "GetVsyncInterruptEvent"}, + {0x00060040, &CAM_C::GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"}, + {0x00070102, &CAM_C::SetReceiving, "SetReceiving"}, + {0x00080040, &CAM_C::IsFinishedReceiving, "IsFinishedReceiving"}, + {0x00090100, &CAM_C::SetTransferLines, "SetTransferLines"}, + {0x000A0080, &CAM_C::GetMaxLines, "GetMaxLines"}, + {0x000B0100, &CAM_C::SetTransferBytes, "SetTransferBytes"}, + {0x000C0040, &CAM_C::GetTransferBytes, "GetTransferBytes"}, + {0x000D0080, &CAM_C::GetMaxBytes, "GetMaxBytes"}, + {0x000E0080, &CAM_C::SetTrimming, "SetTrimming"}, + {0x000F0040, &CAM_C::IsTrimming, "IsTrimming"}, + {0x00100140, &CAM_C::SetTrimmingParams, "SetTrimmingParams"}, + {0x00110040, &CAM_C::GetTrimmingParams, "GetTrimmingParams"}, + {0x00120140, &CAM_C::SetTrimmingParamsCenter, "SetTrimmingParamsCenter"}, + {0x00130040, &CAM_C::Activate, "Activate"}, + {0x00140080, &CAM_C::SwitchContext, "SwitchContext"}, + {0x00150080, nullptr, "SetExposure"}, + {0x00160080, nullptr, "SetWhiteBalance"}, + {0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"}, + {0x00180080, nullptr, "SetSharpness"}, + {0x00190080, nullptr, "SetAutoExposure"}, + {0x001A0040, nullptr, "IsAutoExposure"}, + {0x001B0080, nullptr, "SetAutoWhiteBalance"}, + {0x001C0040, nullptr, "IsAutoWhiteBalance"}, + {0x001D00C0, &CAM_C::FlipImage, "FlipImage"}, + {0x001E0200, &CAM_C::SetDetailSize, "SetDetailSize"}, + {0x001F00C0, &CAM_C::SetSize, "SetSize"}, + {0x00200080, &CAM_C::SetFrameRate, "SetFrameRate"}, + {0x00210080, nullptr, "SetPhotoMode"}, + {0x002200C0, &CAM_C::SetEffect, "SetEffect"}, + {0x00230080, nullptr, "SetContrast"}, + {0x00240080, nullptr, "SetLensCorrection"}, + {0x002500C0, &CAM_C::SetOutputFormat, "SetOutputFormat"}, + {0x00260140, nullptr, "SetAutoExposureWindow"}, + {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, + {0x00280080, nullptr, "SetNoiseFilter"}, + {0x00290080, &CAM_C::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, + {0x002A0080, nullptr, "GetLatestVsyncTiming"}, + {0x002B0000, &CAM_C::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, + {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, + {0x002D00C0, nullptr, "WriteRegisterI2c"}, + {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, + {0x002F0080, nullptr, "ReadRegisterI2cExclusive"}, + {0x00300080, nullptr, "ReadMcuVariableI2cExclusive"}, + {0x00310180, nullptr, "SetImageQualityCalibrationData"}, + {0x00320000, nullptr, "GetImageQualityCalibrationData"}, + {0x003302C0, &CAM_C::SetPackageParameterWithoutContext, + "SetPackageParameterWithoutContext"}, + {0x00340140, &CAM_C::SetPackageParameterWithContext, "SetPackageParameterWithContext"}, + {0x003501C0, &CAM_C::SetPackageParameterWithContextDetail, + "SetPackageParameterWithContextDetail"}, + {0x00360000, &CAM_C::GetSuitableY2rStandardCoefficient, + "GetSuitableY2rStandardCoefficient"}, + {0x00370202, nullptr, "PlayShutterSoundWithWave"}, + {0x00380040, &CAM_C::PlayShutterSound, "PlayShutterSound"}, + {0x00390000, &CAM_C::DriverInitialize, "DriverInitialize"}, + {0x003A0000, &CAM_C::DriverFinalize, "DriverFinalize"}, + {0x003B0000, nullptr, "GetActivatedCamera"}, + {0x003C0000, nullptr, "GetSleepCamera"}, + {0x003D0040, nullptr, "SetSleepCamera"}, + {0x003E0040, nullptr, "SetBrightnessSynchronization"}, + }; + RegisterHandlers(functions); } } // namespace CAM diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h index 6b296c00d..e68887c57 100644 --- a/src/core/hle/service/cam/cam_c.h +++ b/src/core/hle/service/cam/cam_c.h @@ -4,18 +4,14 @@ #pragma once -#include "core/hle/service/service.h" +#include "core/hle/service/cam/cam.h" namespace Service { namespace CAM { -class CAM_C_Interface : public Service::Interface { +class CAM_C final : public Module::Interface { public: - CAM_C_Interface(); - - std::string GetPortName() const override { - return "cam:c"; - } + explicit CAM_C(std::shared_ptr cam); }; } // namespace CAM diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp index 2ba853606..ed4067f4c 100644 --- a/src/core/hle/service/cam/cam_q.cpp +++ b/src/core/hle/service/cam/cam_q.cpp @@ -7,11 +7,10 @@ namespace Service { namespace CAM { -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -CAM_Q_Interface::CAM_Q_Interface() { - // Register(FunctionTable); +CAM_Q::CAM_Q() : ServiceFramework("cam:q", 1 /*TODO: find the true value*/) { + // Empty arrays are illegal -- commented out until an entry is added. + // static const FunctionInfo functions[] = {}; + // RegisterHandlers(functions); } } // namespace CAM diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h index 07cc12534..a96698668 100644 --- a/src/core/hle/service/cam/cam_q.h +++ b/src/core/hle/service/cam/cam_q.h @@ -9,13 +9,9 @@ namespace Service { namespace CAM { -class CAM_Q_Interface : public Service::Interface { +class CAM_Q : public ServiceFramework { public: - CAM_Q_Interface(); - - std::string GetPortName() const override { - return "cam:q"; - } + CAM_Q(); }; } // namespace CAM diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp index f1c6da587..5e8bd1cd9 100644 --- a/src/core/hle/service/cam/cam_s.cpp +++ b/src/core/hle/service/cam/cam_s.cpp @@ -2,16 +2,81 @@ // 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_s.h" namespace Service { namespace CAM { -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -CAM_S_Interface::CAM_S_Interface() { - // Register(FunctionTable); +CAM_S::CAM_S(std::shared_ptr cam) : Module::Interface(std::move(cam), "cam:s", 1) { + static const FunctionInfo functions[] = { + {0x00010040, &CAM_S::StartCapture, "StartCapture"}, + {0x00020040, &CAM_S::StopCapture, "StopCapture"}, + {0x00030040, &CAM_S::IsBusy, "IsBusy"}, + {0x00040040, &CAM_S::ClearBuffer, "ClearBuffer"}, + {0x00050040, &CAM_S::GetVsyncInterruptEvent, "GetVsyncInterruptEvent"}, + {0x00060040, &CAM_S::GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"}, + {0x00070102, &CAM_S::SetReceiving, "SetReceiving"}, + {0x00080040, &CAM_S::IsFinishedReceiving, "IsFinishedReceiving"}, + {0x00090100, &CAM_S::SetTransferLines, "SetTransferLines"}, + {0x000A0080, &CAM_S::GetMaxLines, "GetMaxLines"}, + {0x000B0100, &CAM_S::SetTransferBytes, "SetTransferBytes"}, + {0x000C0040, &CAM_S::GetTransferBytes, "GetTransferBytes"}, + {0x000D0080, &CAM_S::GetMaxBytes, "GetMaxBytes"}, + {0x000E0080, &CAM_S::SetTrimming, "SetTrimming"}, + {0x000F0040, &CAM_S::IsTrimming, "IsTrimming"}, + {0x00100140, &CAM_S::SetTrimmingParams, "SetTrimmingParams"}, + {0x00110040, &CAM_S::GetTrimmingParams, "GetTrimmingParams"}, + {0x00120140, &CAM_S::SetTrimmingParamsCenter, "SetTrimmingParamsCenter"}, + {0x00130040, &CAM_S::Activate, "Activate"}, + {0x00140080, &CAM_S::SwitchContext, "SwitchContext"}, + {0x00150080, nullptr, "SetExposure"}, + {0x00160080, nullptr, "SetWhiteBalance"}, + {0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"}, + {0x00180080, nullptr, "SetSharpness"}, + {0x00190080, nullptr, "SetAutoExposure"}, + {0x001A0040, nullptr, "IsAutoExposure"}, + {0x001B0080, nullptr, "SetAutoWhiteBalance"}, + {0x001C0040, nullptr, "IsAutoWhiteBalance"}, + {0x001D00C0, &CAM_S::FlipImage, "FlipImage"}, + {0x001E0200, &CAM_S::SetDetailSize, "SetDetailSize"}, + {0x001F00C0, &CAM_S::SetSize, "SetSize"}, + {0x00200080, &CAM_S::SetFrameRate, "SetFrameRate"}, + {0x00210080, nullptr, "SetPhotoMode"}, + {0x002200C0, &CAM_S::SetEffect, "SetEffect"}, + {0x00230080, nullptr, "SetContrast"}, + {0x00240080, nullptr, "SetLensCorrection"}, + {0x002500C0, &CAM_S::SetOutputFormat, "SetOutputFormat"}, + {0x00260140, nullptr, "SetAutoExposureWindow"}, + {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, + {0x00280080, nullptr, "SetNoiseFilter"}, + {0x00290080, &CAM_S::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, + {0x002A0080, nullptr, "GetLatestVsyncTiming"}, + {0x002B0000, &CAM_S::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, + {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, + {0x002D00C0, nullptr, "WriteRegisterI2c"}, + {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, + {0x002F0080, nullptr, "ReadRegisterI2cExclusive"}, + {0x00300080, nullptr, "ReadMcuVariableI2cExclusive"}, + {0x00310180, nullptr, "SetImageQualityCalibrationData"}, + {0x00320000, nullptr, "GetImageQualityCalibrationData"}, + {0x003302C0, &CAM_S::SetPackageParameterWithoutContext, + "SetPackageParameterWithoutContext"}, + {0x00340140, &CAM_S::SetPackageParameterWithContext, "SetPackageParameterWithContext"}, + {0x003501C0, &CAM_S::SetPackageParameterWithContextDetail, + "SetPackageParameterWithContextDetail"}, + {0x00360000, &CAM_S::GetSuitableY2rStandardCoefficient, + "GetSuitableY2rStandardCoefficient"}, + {0x00370202, nullptr, "PlayShutterSoundWithWave"}, + {0x00380040, &CAM_S::PlayShutterSound, "PlayShutterSound"}, + {0x00390000, &CAM_S::DriverInitialize, "DriverInitialize"}, + {0x003A0000, &CAM_S::DriverFinalize, "DriverFinalize"}, + {0x003B0000, nullptr, "GetActivatedCamera"}, + {0x003C0000, nullptr, "GetSleepCamera"}, + {0x003D0040, nullptr, "SetSleepCamera"}, + {0x003E0040, nullptr, "SetBrightnessSynchronization"}, + }; + RegisterHandlers(functions); } } // namespace CAM diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h index 0a5d6fca2..f958b4261 100644 --- a/src/core/hle/service/cam/cam_s.h +++ b/src/core/hle/service/cam/cam_s.h @@ -4,18 +4,14 @@ #pragma once -#include "core/hle/service/service.h" +#include "core/hle/service/cam/cam.h" namespace Service { namespace CAM { -class CAM_S_Interface : public Service::Interface { +class CAM_S final : public Module::Interface { public: - CAM_S_Interface(); - - std::string GetPortName() const override { - return "cam:s"; - } + explicit CAM_S(std::shared_ptr cam); }; } // namespace CAM diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp index 251c1e6d4..f4e23ec30 100644 --- a/src/core/hle/service/cam/cam_u.cpp +++ b/src/core/hle/service/cam/cam_u.cpp @@ -8,73 +8,75 @@ namespace Service { namespace CAM { -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, StartCapture, "StartCapture"}, - {0x00020040, StopCapture, "StopCapture"}, - {0x00030040, IsBusy, "IsBusy"}, - {0x00040040, ClearBuffer, "ClearBuffer"}, - {0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"}, - {0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"}, - {0x00070102, SetReceiving, "SetReceiving"}, - {0x00080040, IsFinishedReceiving, "IsFinishedReceiving"}, - {0x00090100, SetTransferLines, "SetTransferLines"}, - {0x000A0080, GetMaxLines, "GetMaxLines"}, - {0x000B0100, SetTransferBytes, "SetTransferBytes"}, - {0x000C0040, GetTransferBytes, "GetTransferBytes"}, - {0x000D0080, GetMaxBytes, "GetMaxBytes"}, - {0x000E0080, SetTrimming, "SetTrimming"}, - {0x000F0040, IsTrimming, "IsTrimming"}, - {0x00100140, SetTrimmingParams, "SetTrimmingParams"}, - {0x00110040, GetTrimmingParams, "GetTrimmingParams"}, - {0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"}, - {0x00130040, Activate, "Activate"}, - {0x00140080, SwitchContext, "SwitchContext"}, - {0x00150080, nullptr, "SetExposure"}, - {0x00160080, nullptr, "SetWhiteBalance"}, - {0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"}, - {0x00180080, nullptr, "SetSharpness"}, - {0x00190080, nullptr, "SetAutoExposure"}, - {0x001A0040, nullptr, "IsAutoExposure"}, - {0x001B0080, nullptr, "SetAutoWhiteBalance"}, - {0x001C0040, nullptr, "IsAutoWhiteBalance"}, - {0x001D00C0, FlipImage, "FlipImage"}, - {0x001E0200, SetDetailSize, "SetDetailSize"}, - {0x001F00C0, SetSize, "SetSize"}, - {0x00200080, SetFrameRate, "SetFrameRate"}, - {0x00210080, nullptr, "SetPhotoMode"}, - {0x002200C0, SetEffect, "SetEffect"}, - {0x00230080, nullptr, "SetContrast"}, - {0x00240080, nullptr, "SetLensCorrection"}, - {0x002500C0, SetOutputFormat, "SetOutputFormat"}, - {0x00260140, nullptr, "SetAutoExposureWindow"}, - {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, - {0x00280080, nullptr, "SetNoiseFilter"}, - {0x00290080, SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, - {0x002A0080, nullptr, "GetLatestVsyncTiming"}, - {0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, - {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, - {0x002D00C0, nullptr, "WriteRegisterI2c"}, - {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, - {0x002F0080, nullptr, "ReadRegisterI2cExclusive"}, - {0x00300080, nullptr, "ReadMcuVariableI2cExclusive"}, - {0x00310180, nullptr, "SetImageQualityCalibrationData"}, - {0x00320000, nullptr, "GetImageQualityCalibrationData"}, - {0x003302C0, SetPackageParameterWithoutContext, "SetPackageParameterWithoutContext"}, - {0x00340140, SetPackageParameterWithContext, "SetPackageParameterWithContext"}, - {0x003501C0, SetPackageParameterWithContextDetail, "SetPackageParameterWithContextDetail"}, - {0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"}, - {0x00370202, nullptr, "PlayShutterSoundWithWave"}, - {0x00380040, PlayShutterSound, "PlayShutterSound"}, - {0x00390000, DriverInitialize, "DriverInitialize"}, - {0x003A0000, DriverFinalize, "DriverFinalize"}, - {0x003B0000, nullptr, "GetActivatedCamera"}, - {0x003C0000, nullptr, "GetSleepCamera"}, - {0x003D0040, nullptr, "SetSleepCamera"}, - {0x003E0040, nullptr, "SetBrightnessSynchronization"}, -}; - -CAM_U_Interface::CAM_U_Interface() { - Register(FunctionTable); +CAM_U::CAM_U(std::shared_ptr cam) : Module::Interface(std::move(cam), "cam:u", 1) { + static const FunctionInfo functions[] = { + {0x00010040, &CAM_U::StartCapture, "StartCapture"}, + {0x00020040, &CAM_U::StopCapture, "StopCapture"}, + {0x00030040, &CAM_U::IsBusy, "IsBusy"}, + {0x00040040, &CAM_U::ClearBuffer, "ClearBuffer"}, + {0x00050040, &CAM_U::GetVsyncInterruptEvent, "GetVsyncInterruptEvent"}, + {0x00060040, &CAM_U::GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"}, + {0x00070102, &CAM_U::SetReceiving, "SetReceiving"}, + {0x00080040, &CAM_U::IsFinishedReceiving, "IsFinishedReceiving"}, + {0x00090100, &CAM_U::SetTransferLines, "SetTransferLines"}, + {0x000A0080, &CAM_U::GetMaxLines, "GetMaxLines"}, + {0x000B0100, &CAM_U::SetTransferBytes, "SetTransferBytes"}, + {0x000C0040, &CAM_U::GetTransferBytes, "GetTransferBytes"}, + {0x000D0080, &CAM_U::GetMaxBytes, "GetMaxBytes"}, + {0x000E0080, &CAM_U::SetTrimming, "SetTrimming"}, + {0x000F0040, &CAM_U::IsTrimming, "IsTrimming"}, + {0x00100140, &CAM_U::SetTrimmingParams, "SetTrimmingParams"}, + {0x00110040, &CAM_U::GetTrimmingParams, "GetTrimmingParams"}, + {0x00120140, &CAM_U::SetTrimmingParamsCenter, "SetTrimmingParamsCenter"}, + {0x00130040, &CAM_U::Activate, "Activate"}, + {0x00140080, &CAM_U::SwitchContext, "SwitchContext"}, + {0x00150080, nullptr, "SetExposure"}, + {0x00160080, nullptr, "SetWhiteBalance"}, + {0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"}, + {0x00180080, nullptr, "SetSharpness"}, + {0x00190080, nullptr, "SetAutoExposure"}, + {0x001A0040, nullptr, "IsAutoExposure"}, + {0x001B0080, nullptr, "SetAutoWhiteBalance"}, + {0x001C0040, nullptr, "IsAutoWhiteBalance"}, + {0x001D00C0, &CAM_U::FlipImage, "FlipImage"}, + {0x001E0200, &CAM_U::SetDetailSize, "SetDetailSize"}, + {0x001F00C0, &CAM_U::SetSize, "SetSize"}, + {0x00200080, &CAM_U::SetFrameRate, "SetFrameRate"}, + {0x00210080, nullptr, "SetPhotoMode"}, + {0x002200C0, &CAM_U::SetEffect, "SetEffect"}, + {0x00230080, nullptr, "SetContrast"}, + {0x00240080, nullptr, "SetLensCorrection"}, + {0x002500C0, &CAM_U::SetOutputFormat, "SetOutputFormat"}, + {0x00260140, nullptr, "SetAutoExposureWindow"}, + {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, + {0x00280080, nullptr, "SetNoiseFilter"}, + {0x00290080, &CAM_U::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, + {0x002A0080, nullptr, "GetLatestVsyncTiming"}, + {0x002B0000, &CAM_U::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, + {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, + {0x002D00C0, nullptr, "WriteRegisterI2c"}, + {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, + {0x002F0080, nullptr, "ReadRegisterI2cExclusive"}, + {0x00300080, nullptr, "ReadMcuVariableI2cExclusive"}, + {0x00310180, nullptr, "SetImageQualityCalibrationData"}, + {0x00320000, nullptr, "GetImageQualityCalibrationData"}, + {0x003302C0, &CAM_U::SetPackageParameterWithoutContext, + "SetPackageParameterWithoutContext"}, + {0x00340140, &CAM_U::SetPackageParameterWithContext, "SetPackageParameterWithContext"}, + {0x003501C0, &CAM_U::SetPackageParameterWithContextDetail, + "SetPackageParameterWithContextDetail"}, + {0x00360000, &CAM_U::GetSuitableY2rStandardCoefficient, + "GetSuitableY2rStandardCoefficient"}, + {0x00370202, nullptr, "PlayShutterSoundWithWave"}, + {0x00380040, &CAM_U::PlayShutterSound, "PlayShutterSound"}, + {0x00390000, &CAM_U::DriverInitialize, "DriverInitialize"}, + {0x003A0000, &CAM_U::DriverFinalize, "DriverFinalize"}, + {0x003B0000, nullptr, "GetActivatedCamera"}, + {0x003C0000, nullptr, "GetSleepCamera"}, + {0x003D0040, nullptr, "SetSleepCamera"}, + {0x003E0040, nullptr, "SetBrightnessSynchronization"}, + }; + RegisterHandlers(functions); } } // namespace CAM diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h index 369264037..a76daf0e3 100644 --- a/src/core/hle/service/cam/cam_u.h +++ b/src/core/hle/service/cam/cam_u.h @@ -4,18 +4,14 @@ #pragma once -#include "core/hle/service/service.h" +#include "core/hle/service/cam/cam.h" namespace Service { namespace CAM { -class CAM_U_Interface : public Service::Interface { +class CAM_U final : public Module::Interface { public: - CAM_U_Interface(); - - std::string GetPortName() const override { - return "cam:u"; - } + explicit CAM_U(std::shared_ptr cam); }; } // namespace CAM diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index d8925f773..33de75f39 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -269,7 +269,7 @@ void Init() { AM::Init(); APT::Init(); BOSS::Init(); - CAM::Init(); + CAM::InstallInterfaces(*SM::g_service_manager); CECD::Init(); CFG::Init(); DLP::Init(); @@ -312,7 +312,6 @@ void Shutdown() { DLP::Shutdown(); CFG::Shutdown(); CECD::Shutdown(); - CAM::Shutdown(); BOSS::Shutdown(); APT::Shutdown(); AM::Shutdown();