Merge pull request #3239 from wwylele/cam-new-frame
cam: convert to ServiceFramework
This commit is contained in:
commit
c23c39132a
|
@ -3,10 +3,6 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
|
||||||
#include <future>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include "common/bit_set.h"
|
#include "common/bit_set.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
@ -14,78 +10,18 @@
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/event.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.h"
|
||||||
#include "core/hle/service/cam/cam_c.h"
|
#include "core/hle/service/cam/cam_c.h"
|
||||||
#include "core/hle/service/cam/cam_q.h"
|
#include "core/hle/service/cam/cam_q.h"
|
||||||
#include "core/hle/service/cam/cam_s.h"
|
#include "core/hle/service/cam/cam_s.h"
|
||||||
#include "core/hle/service/cam/cam_u.h"
|
#include "core/hle/service/cam/cam_u.h"
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct ContextConfig {
|
|
||||||
Flip flip;
|
|
||||||
Effect effect;
|
|
||||||
OutputFormat format;
|
|
||||||
Resolution resolution;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CameraConfig {
|
|
||||||
std::unique_ptr<Camera::CameraInterface> impl;
|
|
||||||
std::array<ContextConfig, 2> 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<Kernel::Event> completion_event;
|
|
||||||
Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event;
|
|
||||||
Kernel::SharedPtr<Kernel::Event> vsync_interrupt_event;
|
|
||||||
|
|
||||||
std::future<std::vector<u16>> 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
|
// built-in resolution parameters
|
||||||
constexpr std::array<Resolution, 8> PRESET_RESOLUTION{{
|
constexpr std::array<Resolution, 8> PRESET_RESOLUTION{{
|
||||||
{640, 480, 0, 0, 639, 479}, // VGA
|
{640, 480, 0, 0, 639, 479}, // VGA
|
||||||
|
@ -115,16 +51,28 @@ constexpr std::array<int, 13> LATENCY_BY_FRAME_RATE{{
|
||||||
33, // Rate_30_To_10
|
33, // Rate_30_To_10
|
||||||
}};
|
}};
|
||||||
|
|
||||||
std::array<CameraConfig, NumCameras> cameras;
|
|
||||||
std::array<PortConfig, 2> ports;
|
|
||||||
CoreTiming::EventType* completion_event_callback;
|
|
||||||
|
|
||||||
const ResultCode ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
|
const ResultCode ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
|
||||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||||
const ResultCode ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM,
|
const ResultCode ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM,
|
||||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
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];
|
PortConfig& port = ports[port_id];
|
||||||
const CameraConfig& camera = cameras[port.camera_id];
|
const CameraConfig& camera = cameras[port.camera_id];
|
||||||
const auto buffer = port.capture_result.get();
|
const auto buffer = port.capture_result.get();
|
||||||
|
@ -165,7 +113,7 @@ void CompletionEventCallBack(u64 port_id, int) {
|
||||||
if (copy_length <= 0) {
|
if (copy_length <= 0) {
|
||||||
break;
|
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_ptr += copy_length;
|
||||||
dest_size_left -= copy_length;
|
dest_size_left -= copy_length;
|
||||||
src_ptr += original_width;
|
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)!",
|
LOG_ERROR(Service_CAM, "The destination size (%u) doesn't match the source (%zu)!",
|
||||||
port.dest_size, buffer_size);
|
port.dest_size, buffer_size);
|
||||||
}
|
}
|
||||||
Memory::WriteBlock(port.dest, buffer.data(), std::min<size_t>(port.dest_size, buffer_size));
|
Memory::WriteBlock(*port.dest_process, port.dest, buffer.data(),
|
||||||
|
std::min<size_t>(port.dest_size, buffer_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
port.is_receiving = false;
|
port.is_receiving = false;
|
||||||
port.completion_event->Signal();
|
port.completion_event->Signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts a receiving process on the specified port. This can only be called when is_busy = true and
|
void Module::StartReceiving(int port_id) {
|
||||||
// is_receiving = false.
|
|
||||||
void StartReceiving(int port_id) {
|
|
||||||
PortConfig& port = ports[port_id];
|
PortConfig& port = ports[port_id];
|
||||||
port.is_receiving = true;
|
port.is_receiving = true;
|
||||||
|
|
||||||
|
@ -202,11 +149,7 @@ void StartReceiving(int port_id) {
|
||||||
completion_event_callback, port_id);
|
completion_event_callback, port_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancels any ongoing receiving processes at the specified port. This is used by functions that
|
void Module::CancelReceiving(int port_id) {
|
||||||
// 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) {
|
|
||||||
if (!ports[port_id].is_receiving)
|
if (!ports[port_id].is_receiving)
|
||||||
return;
|
return;
|
||||||
LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process.");
|
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;
|
ports[port_id].is_receiving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activates the specified port with the specfied camera.
|
void Module::ActivatePort(int port_id, int camera_id) {
|
||||||
static void ActivatePort(int port_id, int camera_id) {
|
|
||||||
if (ports[port_id].is_busy && ports[port_id].camera_id != camera_id) {
|
if (ports[port_id].is_busy && ports[port_id].camera_id != camera_id) {
|
||||||
CancelReceiving(port_id);
|
CancelReceiving(port_id);
|
||||||
cameras[ports[port_id].camera_id].impl->StopCapture();
|
cameras[ports[port_id].camera_id].impl->StopCapture();
|
||||||
|
@ -244,27 +186,30 @@ using PortSet = CommandParamBitSet<2>;
|
||||||
using ContextSet = CommandParamBitSet<2>;
|
using ContextSet = CommandParamBitSet<2>;
|
||||||
using CameraSet = CommandParamBitSet<3>;
|
using CameraSet = CommandParamBitSet<3>;
|
||||||
|
|
||||||
} // namespace
|
Module::Interface::Interface(std::shared_ptr<Module> cam, const char* name, u32 max_session)
|
||||||
|
: ServiceFramework(name, max_session), cam(std::move(cam)) {}
|
||||||
|
|
||||||
void StartCapture(Service::Interface* self) {
|
Module::Interface::~Interface() = default;
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0);
|
|
||||||
|
void Module::Interface::StartCapture(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp(ctx, 0x01, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
if (!ports[i].is_busy) {
|
if (!cam->ports[i].is_busy) {
|
||||||
if (!ports[i].is_active) {
|
if (!cam->ports[i].is_active) {
|
||||||
// This doesn't return an error, but seems to put the camera in an undefined
|
// This doesn't return an error, but seems to put the camera in an undefined
|
||||||
// state
|
// state
|
||||||
LOG_ERROR(Service_CAM, "port %u hasn't been activated", i);
|
LOG_ERROR(Service_CAM, "port %u hasn't been activated", i);
|
||||||
} else {
|
} else {
|
||||||
cameras[ports[i].camera_id].impl->StartCapture();
|
cam->cameras[cam->ports[i].camera_id].impl->StartCapture();
|
||||||
ports[i].is_busy = true;
|
cam->ports[i].is_busy = true;
|
||||||
if (ports[i].is_pending_receiving) {
|
if (cam->ports[i].is_pending_receiving) {
|
||||||
ports[i].is_pending_receiving = false;
|
cam->ports[i].is_pending_receiving = false;
|
||||||
StartReceiving(i);
|
cam->StartReceiving(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -280,18 +225,18 @@ void StartCapture(Service::Interface* self) {
|
||||||
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopCapture(Service::Interface* self) {
|
void Module::Interface::StopCapture(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0);
|
IPC::RequestParser rp(ctx, 0x02, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
if (ports[i].is_busy) {
|
if (cam->ports[i].is_busy) {
|
||||||
CancelReceiving(i);
|
cam->CancelReceiving(i);
|
||||||
cameras[ports[i].camera_id].impl->StopCapture();
|
cam->cameras[cam->ports[i].camera_id].impl->StopCapture();
|
||||||
ports[i].is_busy = false;
|
cam->ports[i].is_busy = false;
|
||||||
} else {
|
} else {
|
||||||
LOG_WARNING(Service_CAM, "port %u already stopped", i);
|
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);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsBusy(Service::Interface* self) {
|
void Module::Interface::IsBusy(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
|
IPC::RequestParser rp(ctx, 0x03, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
|
@ -315,7 +260,7 @@ void IsBusy(Service::Interface* self) {
|
||||||
bool is_busy = true;
|
bool is_busy = true;
|
||||||
// Note: the behaviour on no or both ports selected are verified against real 3DS.
|
// Note: the behaviour on no or both ports selected are verified against real 3DS.
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
is_busy &= ports[i].is_busy;
|
is_busy &= cam->ports[i].is_busy;
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(is_busy);
|
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);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearBuffer(Service::Interface* self) {
|
void Module::Interface::ClearBuffer(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0);
|
IPC::RequestParser rp(ctx, 0x04, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
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);
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetVsyncInterruptEvent(Service::Interface* self) {
|
void Module::Interface::GetVsyncInterruptEvent(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0);
|
IPC::RequestParser rp(ctx, 0x05, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port = *port_select.begin();
|
int port = *port_select.begin();
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyHandles(
|
rb.PushCopyObjects(cam->ports[port].vsync_interrupt_event);
|
||||||
Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).Unwrap());
|
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
||||||
rb.PushCopyHandles(0);
|
rb.PushCopyObjects<Kernel::Object>(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetBufferErrorInterruptEvent(Service::Interface* self) {
|
void Module::Interface::GetBufferErrorInterruptEvent(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0);
|
IPC::RequestParser rp(ctx, 0x06, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port = *port_select.begin();
|
int port = *port_select.begin();
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyHandles(
|
rb.PushCopyObjects(cam->ports[port].buffer_error_interrupt_event);
|
||||||
Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).Unwrap());
|
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
||||||
rb.PushCopyHandles(0);
|
rb.PushCopyObjects<Kernel::Object>(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetReceiving(Service::Interface* self) {
|
void Module::Interface::SetReceiving(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2);
|
IPC::RequestParser rp(ctx, 0x07, 4, 2);
|
||||||
const VAddr dest = rp.Pop<u32>();
|
const VAddr dest = rp.Pop<u32>();
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
const u32 image_size = rp.Pop<u32>();
|
const u32 image_size = rp.Pop<u32>();
|
||||||
const u16 trans_unit = rp.Pop<u16>();
|
const u16 trans_unit = rp.Pop<u16>();
|
||||||
rp.PopHandle(); // Handle to destination process. not used
|
auto process = rp.PopObject<Kernel::Process>();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port_id = *port_select.begin();
|
int port_id = *port_select.begin();
|
||||||
PortConfig& port = ports[port_id];
|
PortConfig& port = cam->ports[port_id];
|
||||||
CancelReceiving(port_id);
|
cam->CancelReceiving(port_id);
|
||||||
port.completion_event->Clear();
|
port.completion_event->Clear();
|
||||||
|
port.dest_process = process.get();
|
||||||
port.dest = dest;
|
port.dest = dest;
|
||||||
port.dest_size = image_size;
|
port.dest_size = image_size;
|
||||||
|
|
||||||
if (port.is_busy) {
|
if (port.is_busy) {
|
||||||
StartReceiving(port_id);
|
cam->StartReceiving(port_id);
|
||||||
} else {
|
} else {
|
||||||
port.is_pending_receiving = true;
|
port.is_pending_receiving = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).Unwrap());
|
rb.PushCopyObjects(port.completion_event);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
||||||
rb.PushCopyHandles(0);
|
rb.PushCopyObjects<Kernel::Object>(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest,
|
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);
|
port_select.m_val, image_size, trans_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsFinishedReceiving(Service::Interface* self) {
|
void Module::Interface::IsFinishedReceiving(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0);
|
IPC::RequestParser rp(ctx, 0x08, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port = *port_select.begin();
|
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(RESULT_SUCCESS);
|
||||||
rb.Push(!is_busy);
|
rb.Push(!is_busy);
|
||||||
} else {
|
} else {
|
||||||
|
@ -430,8 +374,8 @@ void IsFinishedReceiving(Service::Interface* self) {
|
||||||
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTransferLines(Service::Interface* self) {
|
void Module::Interface::SetTransferLines(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0);
|
IPC::RequestParser rp(ctx, 0x09, 4, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
const u16 transfer_lines = rp.Pop<u16>();
|
const u16 transfer_lines = rp.Pop<u16>();
|
||||||
const u16 width = rp.Pop<u16>();
|
const u16 width = rp.Pop<u16>();
|
||||||
|
@ -440,7 +384,7 @@ void SetTransferLines(Service::Interface* self) {
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
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);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
|
@ -452,8 +396,8 @@ void SetTransferLines(Service::Interface* self) {
|
||||||
port_select.m_val, transfer_lines, width, height);
|
port_select.m_val, transfer_lines, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetMaxLines(Service::Interface* self) {
|
void Module::Interface::GetMaxLines(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0);
|
IPC::RequestParser rp(ctx, 0x0A, 2, 0);
|
||||||
const u16 width = rp.Pop<u16>();
|
const u16 width = rp.Pop<u16>();
|
||||||
const u16 height = rp.Pop<u16>();
|
const u16 height = rp.Pop<u16>();
|
||||||
|
|
||||||
|
@ -485,8 +429,8 @@ void GetMaxLines(Service::Interface* self) {
|
||||||
LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
|
LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTransferBytes(Service::Interface* self) {
|
void Module::Interface::SetTransferBytes(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0);
|
IPC::RequestParser rp(ctx, 0x0B, 4, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
const u16 transfer_bytes = rp.Pop<u16>();
|
const u16 transfer_bytes = rp.Pop<u16>();
|
||||||
const u16 width = rp.Pop<u16>();
|
const u16 width = rp.Pop<u16>();
|
||||||
|
@ -495,7 +439,7 @@ void SetTransferBytes(Service::Interface* self) {
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
ports[i].transfer_bytes = transfer_bytes;
|
cam->ports[i].transfer_bytes = transfer_bytes;
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
|
@ -507,15 +451,15 @@ void SetTransferBytes(Service::Interface* self) {
|
||||||
port_select.m_val, transfer_bytes, width, height);
|
port_select.m_val, transfer_bytes, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetTransferBytes(Service::Interface* self) {
|
void Module::Interface::GetTransferBytes(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0);
|
IPC::RequestParser rp(ctx, 0x0C, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port = *port_select.begin();
|
int port = *port_select.begin();
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(ports[port].transfer_bytes);
|
rb.Push(cam->ports[port].transfer_bytes);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
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);
|
LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetMaxBytes(Service::Interface* self) {
|
void Module::Interface::GetMaxBytes(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0);
|
IPC::RequestParser rp(ctx, 0x0D, 2, 0);
|
||||||
const u16 width = rp.Pop<u16>();
|
const u16 width = rp.Pop<u16>();
|
||||||
const u16 height = rp.Pop<u16>();
|
const u16 height = rp.Pop<u16>();
|
||||||
|
|
||||||
|
@ -552,15 +496,15 @@ void GetMaxBytes(Service::Interface* self) {
|
||||||
LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
|
LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTrimming(Service::Interface* self) {
|
void Module::Interface::SetTrimming(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0);
|
IPC::RequestParser rp(ctx, 0x0E, 2, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
const bool trim = rp.Pop<bool>();
|
const bool trim = rp.Pop<bool>();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
ports[i].is_trimming = trim;
|
cam->ports[i].is_trimming = trim;
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else {
|
} 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);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsTrimming(Service::Interface* self) {
|
void Module::Interface::IsTrimming(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0);
|
IPC::RequestParser rp(ctx, 0x0F, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port = *port_select.begin();
|
int port = *port_select.begin();
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(ports[port].is_trimming);
|
rb.Push(cam->ports[port].is_trimming);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
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);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTrimmingParams(Service::Interface* self) {
|
void Module::Interface::SetTrimmingParams(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0);
|
IPC::RequestParser rp(ctx, 0x10, 5, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
const u16 x0 = rp.Pop<u16>();
|
const u16 x0 = rp.Pop<u16>();
|
||||||
const u16 y0 = rp.Pop<u16>();
|
const u16 y0 = rp.Pop<u16>();
|
||||||
|
@ -600,10 +544,10 @@ void SetTrimmingParams(Service::Interface* self) {
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
ports[i].x0 = x0;
|
cam->ports[i].x0 = x0;
|
||||||
ports[i].y0 = y0;
|
cam->ports[i].y0 = y0;
|
||||||
ports[i].x1 = x1;
|
cam->ports[i].x1 = x1;
|
||||||
ports[i].y1 = y1;
|
cam->ports[i].y1 = y1;
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
|
@ -615,18 +559,18 @@ void SetTrimmingParams(Service::Interface* self) {
|
||||||
x0, y0, x1, y1);
|
x0, y0, x1, y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetTrimmingParams(Service::Interface* self) {
|
void Module::Interface::GetTrimmingParams(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0);
|
IPC::RequestParser rp(ctx, 0x11, 1, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
|
||||||
if (port_select.IsSingle()) {
|
if (port_select.IsSingle()) {
|
||||||
int port = *port_select.begin();
|
int port = *port_select.begin();
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(ports[port].x0);
|
rb.Push(cam->ports[port].x0);
|
||||||
rb.Push(ports[port].y0);
|
rb.Push(cam->ports[port].y0);
|
||||||
rb.Push(ports[port].x1);
|
rb.Push(cam->ports[port].x1);
|
||||||
rb.Push(ports[port].y1);
|
rb.Push(cam->ports[port].y1);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
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);
|
LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTrimmingParamsCenter(Service::Interface* self) {
|
void Module::Interface::SetTrimmingParamsCenter(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0);
|
IPC::RequestParser rp(ctx, 0x12, 5, 0);
|
||||||
const PortSet port_select(rp.Pop<u8>());
|
const PortSet port_select(rp.Pop<u8>());
|
||||||
const u16 trim_w = rp.Pop<u16>();
|
const u16 trim_w = rp.Pop<u16>();
|
||||||
const u16 trim_h = rp.Pop<u16>();
|
const u16 trim_h = rp.Pop<u16>();
|
||||||
|
@ -647,10 +591,10 @@ void SetTrimmingParamsCenter(Service::Interface* self) {
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (port_select.IsValid()) {
|
if (port_select.IsValid()) {
|
||||||
for (int i : port_select) {
|
for (int i : port_select) {
|
||||||
ports[i].x0 = (cam_w - trim_w) / 2;
|
cam->ports[i].x0 = (cam_w - trim_w) / 2;
|
||||||
ports[i].y0 = (cam_h - trim_h) / 2;
|
cam->ports[i].y0 = (cam_h - trim_h) / 2;
|
||||||
ports[i].x1 = ports[i].x0 + trim_w;
|
cam->ports[i].x1 = cam->ports[i].x0 + trim_w;
|
||||||
ports[i].y1 = ports[i].y0 + trim_h;
|
cam->ports[i].y1 = cam->ports[i].y0 + trim_h;
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
|
@ -662,20 +606,20 @@ void SetTrimmingParamsCenter(Service::Interface* self) {
|
||||||
port_select.m_val, trim_w, trim_h, cam_w, cam_h);
|
port_select.m_val, trim_w, trim_h, cam_w, cam_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activate(Service::Interface* self) {
|
void Module::Interface::Activate(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0);
|
IPC::RequestParser rp(ctx, 0x13, 1, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (camera_select.IsValid()) {
|
if (camera_select.IsValid()) {
|
||||||
if (camera_select.m_val == 0) { // deactive all
|
if (camera_select.m_val == 0) { // deactive all
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
if (ports[i].is_busy) {
|
if (cam->ports[i].is_busy) {
|
||||||
CancelReceiving(i);
|
cam->CancelReceiving(i);
|
||||||
cameras[ports[i].camera_id].impl->StopCapture();
|
cam->cameras[cam->ports[i].camera_id].impl->StopCapture();
|
||||||
ports[i].is_busy = false;
|
cam->ports[i].is_busy = false;
|
||||||
}
|
}
|
||||||
ports[i].is_active = false;
|
cam->ports[i].is_active = false;
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else if (camera_select[0] && camera_select[1]) {
|
} else if (camera_select[0] && camera_select[1]) {
|
||||||
|
@ -683,13 +627,13 @@ void Activate(Service::Interface* self) {
|
||||||
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
rb.Push(ERROR_INVALID_ENUM_VALUE);
|
||||||
} else {
|
} else {
|
||||||
if (camera_select[0]) {
|
if (camera_select[0]) {
|
||||||
ActivatePort(0, 0);
|
cam->ActivatePort(0, 0);
|
||||||
} else if (camera_select[1]) {
|
} else if (camera_select[1]) {
|
||||||
ActivatePort(0, 1);
|
cam->ActivatePort(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (camera_select[2]) {
|
if (camera_select[2]) {
|
||||||
ActivatePort(1, 2);
|
cam->ActivatePort(1, 2);
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
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);
|
LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchContext(Service::Interface* self) {
|
void Module::Interface::SwitchContext(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0);
|
IPC::RequestParser rp(ctx, 0x14, 2, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
const ContextSet context_select(rp.Pop<u8>());
|
const ContextSet context_select(rp.Pop<u8>());
|
||||||
|
|
||||||
|
@ -710,12 +654,12 @@ void SwitchContext(Service::Interface* self) {
|
||||||
if (camera_select.IsValid() && context_select.IsSingle()) {
|
if (camera_select.IsValid() && context_select.IsSingle()) {
|
||||||
int context = *context_select.begin();
|
int context = *context_select.begin();
|
||||||
for (int camera : camera_select) {
|
for (int camera : camera_select) {
|
||||||
cameras[camera].current_context = context;
|
cam->cameras[camera].current_context = context;
|
||||||
const ContextConfig& context_config = cameras[camera].contexts[context];
|
const ContextConfig& context_config = cam->cameras[camera].contexts[context];
|
||||||
cameras[camera].impl->SetFlip(context_config.flip);
|
cam->cameras[camera].impl->SetFlip(context_config.flip);
|
||||||
cameras[camera].impl->SetEffect(context_config.effect);
|
cam->cameras[camera].impl->SetEffect(context_config.effect);
|
||||||
cameras[camera].impl->SetFormat(context_config.format);
|
cam->cameras[camera].impl->SetFormat(context_config.format);
|
||||||
cameras[camera].impl->SetResolution(context_config.resolution);
|
cam->cameras[camera].impl->SetResolution(context_config.resolution);
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
|
@ -728,8 +672,8 @@ void SwitchContext(Service::Interface* self) {
|
||||||
context_select.m_val);
|
context_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlipImage(Service::Interface* self) {
|
void Module::Interface::FlipImage(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0);
|
IPC::RequestParser rp(ctx, 0x1D, 3, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
const Flip flip = static_cast<Flip>(rp.Pop<u8>());
|
const Flip flip = static_cast<Flip>(rp.Pop<u8>());
|
||||||
const ContextSet context_select(rp.Pop<u8>());
|
const ContextSet context_select(rp.Pop<u8>());
|
||||||
|
@ -738,9 +682,9 @@ void FlipImage(Service::Interface* self) {
|
||||||
if (camera_select.IsValid() && context_select.IsValid()) {
|
if (camera_select.IsValid() && context_select.IsValid()) {
|
||||||
for (int camera : camera_select) {
|
for (int camera : camera_select) {
|
||||||
for (int context : context_select) {
|
for (int context : context_select) {
|
||||||
cameras[camera].contexts[context].flip = flip;
|
cam->cameras[camera].contexts[context].flip = flip;
|
||||||
if (cameras[camera].current_context == context) {
|
if (cam->cameras[camera].current_context == context) {
|
||||||
cameras[camera].impl->SetFlip(flip);
|
cam->cameras[camera].impl->SetFlip(flip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -755,8 +699,8 @@ void FlipImage(Service::Interface* self) {
|
||||||
camera_select.m_val, static_cast<int>(flip), context_select.m_val);
|
camera_select.m_val, static_cast<int>(flip), context_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDetailSize(Service::Interface* self) {
|
void Module::Interface::SetDetailSize(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0);
|
IPC::RequestParser rp(ctx, 0x1E, 8, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
Resolution resolution;
|
Resolution resolution;
|
||||||
resolution.width = rp.Pop<u16>();
|
resolution.width = rp.Pop<u16>();
|
||||||
|
@ -771,9 +715,9 @@ void SetDetailSize(Service::Interface* self) {
|
||||||
if (camera_select.IsValid() && context_select.IsValid()) {
|
if (camera_select.IsValid() && context_select.IsValid()) {
|
||||||
for (int camera : camera_select) {
|
for (int camera : camera_select) {
|
||||||
for (int context : context_select) {
|
for (int context : context_select) {
|
||||||
cameras[camera].contexts[context].resolution = resolution;
|
cam->cameras[camera].contexts[context].resolution = resolution;
|
||||||
if (cameras[camera].current_context == context) {
|
if (cam->cameras[camera].current_context == context) {
|
||||||
cameras[camera].impl->SetResolution(resolution);
|
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);
|
resolution.crop_y0, resolution.crop_x1, resolution.crop_y1, context_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSize(Service::Interface* self) {
|
void Module::Interface::SetSize(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0);
|
IPC::RequestParser rp(ctx, 0x1F, 3, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
const u8 size = rp.Pop<u8>();
|
const u8 size = rp.Pop<u8>();
|
||||||
const ContextSet context_select(rp.Pop<u8>());
|
const ContextSet context_select(rp.Pop<u8>());
|
||||||
|
@ -800,9 +744,9 @@ void SetSize(Service::Interface* self) {
|
||||||
if (camera_select.IsValid() && context_select.IsValid()) {
|
if (camera_select.IsValid() && context_select.IsValid()) {
|
||||||
for (int camera : camera_select) {
|
for (int camera : camera_select) {
|
||||||
for (int context : context_select) {
|
for (int context : context_select) {
|
||||||
cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size];
|
cam->cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size];
|
||||||
if (cameras[camera].current_context == context) {
|
if (cam->cameras[camera].current_context == context) {
|
||||||
cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]);
|
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);
|
camera_select.m_val, size, context_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFrameRate(Service::Interface* self) {
|
void Module::Interface::SetFrameRate(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0);
|
IPC::RequestParser rp(ctx, 0x20, 2, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
|
const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
if (camera_select.IsValid()) {
|
if (camera_select.IsValid()) {
|
||||||
for (int camera : camera_select) {
|
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
|
// TODO(wwylele): consider hinting the actual camera with the expected frame rate
|
||||||
}
|
}
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -838,8 +782,8 @@ void SetFrameRate(Service::Interface* self) {
|
||||||
camera_select.m_val, static_cast<int>(frame_rate));
|
camera_select.m_val, static_cast<int>(frame_rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEffect(Service::Interface* self) {
|
void Module::Interface::SetEffect(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0);
|
IPC::RequestParser rp(ctx, 0x22, 3, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
const Effect effect = static_cast<Effect>(rp.Pop<u8>());
|
const Effect effect = static_cast<Effect>(rp.Pop<u8>());
|
||||||
const ContextSet context_select(rp.Pop<u8>());
|
const ContextSet context_select(rp.Pop<u8>());
|
||||||
|
@ -848,9 +792,9 @@ void SetEffect(Service::Interface* self) {
|
||||||
if (camera_select.IsValid() && context_select.IsValid()) {
|
if (camera_select.IsValid() && context_select.IsValid()) {
|
||||||
for (int camera : camera_select) {
|
for (int camera : camera_select) {
|
||||||
for (int context : context_select) {
|
for (int context : context_select) {
|
||||||
cameras[camera].contexts[context].effect = effect;
|
cam->cameras[camera].contexts[context].effect = effect;
|
||||||
if (cameras[camera].current_context == context) {
|
if (cam->cameras[camera].current_context == context) {
|
||||||
cameras[camera].impl->SetEffect(effect);
|
cam->cameras[camera].impl->SetEffect(effect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -865,8 +809,8 @@ void SetEffect(Service::Interface* self) {
|
||||||
camera_select.m_val, static_cast<int>(effect), context_select.m_val);
|
camera_select.m_val, static_cast<int>(effect), context_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetOutputFormat(Service::Interface* self) {
|
void Module::Interface::SetOutputFormat(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0);
|
IPC::RequestParser rp(ctx, 0x25, 3, 0);
|
||||||
const CameraSet camera_select(rp.Pop<u8>());
|
const CameraSet camera_select(rp.Pop<u8>());
|
||||||
const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
|
const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
|
||||||
const ContextSet context_select(rp.Pop<u8>());
|
const ContextSet context_select(rp.Pop<u8>());
|
||||||
|
@ -875,9 +819,9 @@ void SetOutputFormat(Service::Interface* self) {
|
||||||
if (camera_select.IsValid() && context_select.IsValid()) {
|
if (camera_select.IsValid() && context_select.IsValid()) {
|
||||||
for (int camera : camera_select) {
|
for (int camera : camera_select) {
|
||||||
for (int context : context_select) {
|
for (int context : context_select) {
|
||||||
cameras[camera].contexts[context].format = format;
|
cam->cameras[camera].contexts[context].format = format;
|
||||||
if (cameras[camera].current_context == context) {
|
if (cam->cameras[camera].current_context == context) {
|
||||||
cameras[camera].impl->SetFormat(format);
|
cam->cameras[camera].impl->SetFormat(format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -892,8 +836,8 @@ void SetOutputFormat(Service::Interface* self) {
|
||||||
camera_select.m_val, static_cast<int>(format), context_select.m_val);
|
camera_select.m_val, static_cast<int>(format), context_select.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronizeVsyncTiming(Service::Interface* self) {
|
void Module::Interface::SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0);
|
IPC::RequestParser rp(ctx, 0x29, 2, 0);
|
||||||
const u8 camera_select1 = rp.Pop<u8>();
|
const u8 camera_select1 = rp.Pop<u8>();
|
||||||
const u8 camera_select2 = rp.Pop<u8>();
|
const u8 camera_select2 = rp.Pop<u8>();
|
||||||
|
|
||||||
|
@ -904,9 +848,8 @@ void SynchronizeVsyncTiming(Service::Interface* self) {
|
||||||
camera_select1, camera_select2);
|
camera_select1, camera_select2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetStereoCameraCalibrationData(Service::Interface* self) {
|
void Module::Interface::GetStereoCameraCalibrationData(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestBuilder rb =
|
IPC::RequestBuilder rb = IPC::RequestParser(ctx, 0x2B, 0, 0).MakeBuilder(17, 0);
|
||||||
IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0);
|
|
||||||
|
|
||||||
// Default values taken from yuriks' 3DS. Valid data is required here or games using the
|
// Default values taken from yuriks' 3DS. Valid data is required here or games using the
|
||||||
// calibration get stuck in an infinite CPU loop.
|
// calibration get stuck in an infinite CPU loop.
|
||||||
|
@ -931,8 +874,8 @@ void GetStereoCameraCalibrationData(Service::Interface* self) {
|
||||||
LOG_TRACE(Service_CAM, "called");
|
LOG_TRACE(Service_CAM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPackageParameterWithoutContext(Service::Interface* self) {
|
void Module::Interface::SetPackageParameterWithoutContext(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0);
|
IPC::RequestParser rp(ctx, 0x33, 11, 0);
|
||||||
|
|
||||||
PackageParameterWithoutContext package;
|
PackageParameterWithoutContext package;
|
||||||
rp.PopRaw(package);
|
rp.PopRaw(package);
|
||||||
|
@ -944,7 +887,7 @@ void SetPackageParameterWithoutContext(Service::Interface* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PackageParameterType>
|
template <typename PackageParameterType>
|
||||||
static ResultCode SetPackageParameter(const PackageParameterType& package) {
|
ResultCode Module::SetPackageParameter(const PackageParameterType& package) {
|
||||||
const CameraSet camera_select(package.camera_select);
|
const CameraSet camera_select(package.camera_select);
|
||||||
const ContextSet context_select(package.context_select);
|
const ContextSet context_select(package.context_select);
|
||||||
|
|
||||||
|
@ -975,34 +918,34 @@ Resolution PackageParameterWithContext::GetResolution() const {
|
||||||
return PRESET_RESOLUTION[static_cast<int>(size)];
|
return PRESET_RESOLUTION[static_cast<int>(size)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPackageParameterWithContext(Service::Interface* self) {
|
void Module::Interface::SetPackageParameterWithContext(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0);
|
IPC::RequestParser rp(ctx, 0x34, 5, 0);
|
||||||
|
|
||||||
PackageParameterWithContext package;
|
PackageParameterWithContext package;
|
||||||
rp.PopRaw(package);
|
rp.PopRaw(package);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
ResultCode result = SetPackageParameter(package);
|
ResultCode result = cam->SetPackageParameter(package);
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
|
|
||||||
LOG_DEBUG(Service_CAM, "called");
|
LOG_DEBUG(Service_CAM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPackageParameterWithContextDetail(Service::Interface* self) {
|
void Module::Interface::SetPackageParameterWithContextDetail(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0);
|
IPC::RequestParser rp(ctx, 0x35, 7, 0);
|
||||||
|
|
||||||
PackageParameterWithContextDetail package;
|
PackageParameterWithContextDetail package;
|
||||||
rp.PopRaw(package);
|
rp.PopRaw(package);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
ResultCode result = SetPackageParameter(package);
|
ResultCode result = cam->SetPackageParameter(package);
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
|
|
||||||
LOG_DEBUG(Service_CAM, "called");
|
LOG_DEBUG(Service_CAM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
|
void Module::Interface::GetSuitableY2rStandardCoefficient(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0);
|
IPC::RequestParser rp(ctx, 0x36, 0, 0);
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0);
|
rb.Push<u32>(0);
|
||||||
|
@ -1010,8 +953,8 @@ void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
|
||||||
LOG_WARNING(Service_CAM, "(STUBBED) called");
|
LOG_WARNING(Service_CAM, "(STUBBED) called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayShutterSound(Service::Interface* self) {
|
void Module::Interface::PlayShutterSound(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0);
|
IPC::RequestParser rp(ctx, 0x38, 1, 0);
|
||||||
u8 sound_id = rp.Pop<u8>();
|
u8 sound_id = rp.Pop<u8>();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
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);
|
LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DriverInitialize(Service::Interface* self) {
|
void Module::Interface::DriverInitialize(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0);
|
IPC::RequestParser rp(ctx, 0x39, 0, 0);
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
for (int camera_id = 0; camera_id < NumCameras; ++camera_id) {
|
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;
|
camera.current_context = 0;
|
||||||
for (int context_id = 0; context_id < 2; ++context_id) {
|
for (int context_id = 0; context_id < 2; ++context_id) {
|
||||||
// Note: the following default values are verified against real 3DS
|
// 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);
|
camera.impl->SetResolution(camera.contexts[0].resolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PortConfig& port : ports) {
|
for (PortConfig& port : cam->ports) {
|
||||||
port.Clear();
|
port.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,14 +996,14 @@ void DriverInitialize(Service::Interface* self) {
|
||||||
LOG_DEBUG(Service_CAM, "called");
|
LOG_DEBUG(Service_CAM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DriverFinalize(Service::Interface* self) {
|
void Module::Interface::DriverFinalize(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0);
|
IPC::RequestParser rp(ctx, 0x3A, 0, 0);
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
CancelReceiving(0);
|
cam->CancelReceiving(0);
|
||||||
CancelReceiving(1);
|
cam->CancelReceiving(1);
|
||||||
|
|
||||||
for (CameraConfig& camera : cameras) {
|
for (CameraConfig& camera : cam->cameras) {
|
||||||
camera.impl = nullptr;
|
camera.impl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1069,36 +1012,31 @@ void DriverFinalize(Service::Interface* self) {
|
||||||
LOG_DEBUG(Service_CAM, "called");
|
LOG_DEBUG(Service_CAM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init() {
|
Module::Module() {
|
||||||
using namespace Kernel;
|
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) {
|
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 =
|
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 =
|
port.vsync_interrupt_event =
|
||||||
Event::Create(ResetType::OneShot, "CAM_U::vsync_interrupt_event");
|
Event::Create(ResetType::OneShot, "CAM::vsync_interrupt_event");
|
||||||
}
|
}
|
||||||
completion_event_callback =
|
completion_event_callback = CoreTiming::RegisterEvent(
|
||||||
CoreTiming::RegisterEvent("CAM_U::CompletionEventCallBack", CompletionEventCallBack);
|
"CAM::CompletionEventCallBack",
|
||||||
|
[this](u64 userdata, int cycles_late) { CompletionEventCallBack(userdata, cycles_late); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
Module::~Module() {
|
||||||
CancelReceiving(0);
|
CancelReceiving(0);
|
||||||
CancelReceiving(1);
|
CancelReceiving(1);
|
||||||
for (PortConfig& port : ports) {
|
}
|
||||||
port.completion_event = nullptr;
|
|
||||||
port.buffer_error_interrupt_event = nullptr;
|
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||||
port.vsync_interrupt_event = nullptr;
|
auto cam = std::make_shared<Module>();
|
||||||
}
|
std::make_shared<CAM_U>(cam)->InstallAsService(service_manager);
|
||||||
for (CameraConfig& camera : cameras) {
|
std::make_shared<CAM_S>(cam)->InstallAsService(service_manager);
|
||||||
camera.impl = nullptr;
|
std::make_shared<CAM_C>(cam)->InstallAsService(service_manager);
|
||||||
}
|
std::make_shared<CAM_Q>()->InstallAsService(service_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -4,12 +4,27 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include <array>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Camera {
|
||||||
|
class CameraInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CoreTiming {
|
||||||
|
class EventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class Process;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
|
@ -221,7 +236,18 @@ struct PackageParameterWithContextDetail {
|
||||||
static_assert(sizeof(PackageParameterWithContextDetail) == 28,
|
static_assert(sizeof(PackageParameterWithContextDetail) == 28,
|
||||||
"PackageParameterWithContextDetail structure size is wrong");
|
"PackageParameterWithContextDetail structure size is wrong");
|
||||||
|
|
||||||
/**
|
class Module final {
|
||||||
|
public:
|
||||||
|
Module();
|
||||||
|
~Module();
|
||||||
|
|
||||||
|
class Interface : public ServiceFramework<Interface> {
|
||||||
|
public:
|
||||||
|
Interface(std::shared_ptr<Module> cam, const char* name, u32 max_session);
|
||||||
|
~Interface();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
* Starts capturing at the selected port.
|
* Starts capturing at the selected port.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00010040
|
* 0: 0x00010040
|
||||||
|
@ -230,9 +256,9 @@ static_assert(sizeof(PackageParameterWithContextDetail) == 28,
|
||||||
* 0: 0x00010040
|
* 0: 0x00010040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void StartCapture(Service::Interface* self);
|
void StartCapture(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops capturing from the selected port.
|
* Stops capturing from the selected port.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00020040
|
* 0: 0x00020040
|
||||||
|
@ -241,9 +267,9 @@ void StartCapture(Service::Interface* self);
|
||||||
* 0: 0x00020040
|
* 0: 0x00020040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void StopCapture(Service::Interface* self);
|
void StopCapture(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether the selected port is currently capturing.
|
* Gets whether the selected port is currently capturing.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00030040
|
* 0: 0x00030040
|
||||||
|
@ -253,9 +279,9 @@ void StopCapture(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* 2: 0 if not capturing, 1 if capturing
|
* 2: 0 if not capturing, 1 if capturing
|
||||||
*/
|
*/
|
||||||
void IsBusy(Service::Interface* self);
|
void IsBusy(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the buffer of selected ports.
|
* Clears the buffer of selected ports.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00040040
|
* 0: 0x00040040
|
||||||
|
@ -264,9 +290,9 @@ void IsBusy(Service::Interface* self);
|
||||||
* 0: 0x00040040
|
* 0: 0x00040040
|
||||||
* 2: ResultCode
|
* 2: ResultCode
|
||||||
*/
|
*/
|
||||||
void ClearBuffer(Service::Interface* self);
|
void ClearBuffer(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown
|
* Unknown
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00050040
|
* 0: 0x00050040
|
||||||
|
@ -277,9 +303,9 @@ void ClearBuffer(Service::Interface* self);
|
||||||
* 2: Descriptor: Handle
|
* 2: Descriptor: Handle
|
||||||
* 3: Event handle
|
* 3: Event handle
|
||||||
*/
|
*/
|
||||||
void GetVsyncInterruptEvent(Service::Interface* self);
|
void GetVsyncInterruptEvent(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown
|
* Unknown
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00060040
|
* 0: 0x00060040
|
||||||
|
@ -290,11 +316,11 @@ void GetVsyncInterruptEvent(Service::Interface* self);
|
||||||
* 2: Descriptor: Handle
|
* 2: Descriptor: Handle
|
||||||
* 3: Event handle
|
* 3: Event handle
|
||||||
*/
|
*/
|
||||||
void GetBufferErrorInterruptEvent(Service::Interface* self);
|
void GetBufferErrorInterruptEvent(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the target buffer to receive a frame of image data and starts the transfer. Each camera
|
* Sets the target buffer to receive a frame of image data and starts the transfer. Each
|
||||||
* port has its own event to signal the end of the transfer.
|
* camera port has its own event to signal the end of the transfer.
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00070102
|
* 0: 0x00070102
|
||||||
|
@ -310,9 +336,9 @@ void GetBufferErrorInterruptEvent(Service::Interface* self);
|
||||||
* 2: Descriptor: Handle
|
* 2: Descriptor: Handle
|
||||||
* 3: Handle to event signalled when transfer finishes
|
* 3: Handle to event signalled when transfer finishes
|
||||||
*/
|
*/
|
||||||
void SetReceiving(Service::Interface* self);
|
void SetReceiving(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether the selected port finished receiving a frame.
|
* Gets whether the selected port finished receiving a frame.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00080040
|
* 0: 0x00080040
|
||||||
|
@ -322,9 +348,9 @@ void SetReceiving(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* 2: 0 if not finished, 1 if finished
|
* 2: 0 if not finished, 1 if finished
|
||||||
*/
|
*/
|
||||||
void IsFinishedReceiving(Service::Interface* self);
|
void IsFinishedReceiving(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of lines the buffer contains.
|
* Sets the number of lines the buffer contains.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00090100
|
* 0: 0x00090100
|
||||||
|
@ -337,9 +363,9 @@ void IsFinishedReceiving(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* @todo figure out how the "buffer" actually works.
|
* @todo figure out how the "buffer" actually works.
|
||||||
*/
|
*/
|
||||||
void SetTransferLines(Service::Interface* self);
|
void SetTransferLines(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum number of lines that fit in the buffer
|
* Gets the maximum number of lines that fit in the buffer
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x000A0080
|
* 0: 0x000A0080
|
||||||
|
@ -351,9 +377,9 @@ void SetTransferLines(Service::Interface* self);
|
||||||
* 2: Maximum number of lines that fit in the buffer
|
* 2: Maximum number of lines that fit in the buffer
|
||||||
* @todo figure out how the "buffer" actually works.
|
* @todo figure out how the "buffer" actually works.
|
||||||
*/
|
*/
|
||||||
void GetMaxLines(Service::Interface* self);
|
void GetMaxLines(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of bytes the buffer contains.
|
* Sets the number of bytes the buffer contains.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x000B0100
|
* 0: 0x000B0100
|
||||||
|
@ -366,9 +392,9 @@ void GetMaxLines(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* @todo figure out how the "buffer" actually works.
|
* @todo figure out how the "buffer" actually works.
|
||||||
*/
|
*/
|
||||||
void SetTransferBytes(Service::Interface* self);
|
void SetTransferBytes(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of bytes to the buffer contains.
|
* Gets the number of bytes to the buffer contains.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x000C0040
|
* 0: 0x000C0040
|
||||||
|
@ -379,9 +405,9 @@ void SetTransferBytes(Service::Interface* self);
|
||||||
* 2: The number of bytes the buffer contains
|
* 2: The number of bytes the buffer contains
|
||||||
* @todo figure out how the "buffer" actually works.
|
* @todo figure out how the "buffer" actually works.
|
||||||
*/
|
*/
|
||||||
void GetTransferBytes(Service::Interface* self);
|
void GetTransferBytes(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum number of bytes that fit in the buffer.
|
* Gets the maximum number of bytes that fit in the buffer.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x000D0080
|
* 0: 0x000D0080
|
||||||
|
@ -393,9 +419,9 @@ void GetTransferBytes(Service::Interface* self);
|
||||||
* 2: Maximum number of bytes that fit in the buffer
|
* 2: Maximum number of bytes that fit in the buffer
|
||||||
* @todo figure out how the "buffer" actually works.
|
* @todo figure out how the "buffer" actually works.
|
||||||
*/
|
*/
|
||||||
void GetMaxBytes(Service::Interface* self);
|
void GetMaxBytes(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables trimming.
|
* Enables or disables trimming.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x000E0080
|
* 0: 0x000E0080
|
||||||
|
@ -405,9 +431,9 @@ void GetMaxBytes(Service::Interface* self);
|
||||||
* 0: 0x000E0040
|
* 0: 0x000E0040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetTrimming(Service::Interface* self);
|
void SetTrimming(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether trimming is enabled.
|
* Gets whether trimming is enabled.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x000F0040
|
* 0: 0x000F0040
|
||||||
|
@ -417,9 +443,9 @@ void SetTrimming(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* 2: u8 bool Enable trimming if true
|
* 2: u8 bool Enable trimming if true
|
||||||
*/
|
*/
|
||||||
void IsTrimming(Service::Interface* self);
|
void IsTrimming(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the position to trim.
|
* Sets the position to trim.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00100140
|
* 0: 0x00100140
|
||||||
|
@ -432,9 +458,9 @@ void IsTrimming(Service::Interface* self);
|
||||||
* 0: 0x00100040
|
* 0: 0x00100040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetTrimmingParams(Service::Interface* self);
|
void SetTrimmingParams(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the position to trim.
|
* Gets the position to trim.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00110040
|
* 0: 0x00110040
|
||||||
|
@ -448,11 +474,11 @@ void SetTrimmingParams(Service::Interface* self);
|
||||||
* 4: x end (exclusive)
|
* 4: x end (exclusive)
|
||||||
* 5: y end (exclusive)
|
* 5: y end (exclusive)
|
||||||
*/
|
*/
|
||||||
void GetTrimmingParams(Service::Interface* self);
|
void GetTrimmingParams(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the position to trim by giving the width and height. The trimming window is always at the
|
* Sets the position to trim by giving the width and height. The trimming window is always
|
||||||
* center.
|
* at the center.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00120140
|
* 0: 0x00120140
|
||||||
* 1: u8 selected port
|
* 1: u8 selected port
|
||||||
|
@ -464,9 +490,9 @@ void GetTrimmingParams(Service::Interface* self);
|
||||||
* 0: 0x00120040
|
* 0: 0x00120040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetTrimmingParamsCenter(Service::Interface* self);
|
void SetTrimmingParamsCenter(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects up to two physical cameras to enable.
|
* Selects up to two physical cameras to enable.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00130040
|
* 0: 0x00130040
|
||||||
|
@ -475,9 +501,9 @@ void SetTrimmingParamsCenter(Service::Interface* self);
|
||||||
* 0: 0x00130040
|
* 0: 0x00130040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void Activate(Service::Interface* self);
|
void Activate(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switches the context of camera settings.
|
* Switches the context of camera settings.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00140080
|
* 0: 0x00140080
|
||||||
|
@ -487,9 +513,9 @@ void Activate(Service::Interface* self);
|
||||||
* 0: 0x00140040
|
* 0: 0x00140040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SwitchContext(Service::Interface* self);
|
void SwitchContext(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets flipping of images
|
* Sets flipping of images
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x001D00C0
|
* 0: 0x001D00C0
|
||||||
|
@ -500,10 +526,11 @@ void SwitchContext(Service::Interface* self);
|
||||||
* 0: 0x001D0040
|
* 0: 0x001D0040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void FlipImage(Service::Interface* self);
|
void FlipImage(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets camera resolution from custom parameters. For more details see the Resolution struct.
|
* Sets camera resolution from custom parameters. For more details see the Resolution
|
||||||
|
* struct.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x001E0200
|
* 0: 0x001E0200
|
||||||
* 1: u8 selected camera
|
* 1: u8 selected camera
|
||||||
|
@ -518,9 +545,9 @@ void FlipImage(Service::Interface* self);
|
||||||
* 0: 0x001E0040
|
* 0: 0x001E0040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetDetailSize(Service::Interface* self);
|
void SetDetailSize(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets camera resolution from preset resolution parameters.
|
* Sets camera resolution from preset resolution parameters.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x001F00C0
|
* 0: 0x001F00C0
|
||||||
|
@ -531,9 +558,9 @@ void SetDetailSize(Service::Interface* self);
|
||||||
* 0: 0x001F0040
|
* 0: 0x001F0040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetSize(Service::Interface* self);
|
void SetSize(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets camera framerate.
|
* Sets camera framerate.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00200080
|
* 0: 0x00200080
|
||||||
|
@ -543,9 +570,9 @@ void SetSize(Service::Interface* self);
|
||||||
* 0: 0x00200040
|
* 0: 0x00200040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetFrameRate(Service::Interface* self);
|
void SetFrameRate(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets effect on the output image
|
* Sets effect on the output image
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x002200C0
|
* 0: 0x002200C0
|
||||||
|
@ -556,9 +583,9 @@ void SetFrameRate(Service::Interface* self);
|
||||||
* 0: 0x00220040
|
* 0: 0x00220040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetEffect(Service::Interface* self);
|
void SetEffect(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets format of the output image
|
* Sets format of the output image
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x002500C0
|
* 0: 0x002500C0
|
||||||
|
@ -569,9 +596,9 @@ void SetEffect(Service::Interface* self);
|
||||||
* 0: 0x00250040
|
* 0: 0x00250040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetOutputFormat(Service::Interface* self);
|
void SetOutputFormat(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronizes the V-Sync timing of two cameras.
|
* Synchronizes the V-Sync timing of two cameras.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00290080
|
* 0: 0x00290080
|
||||||
|
@ -581,10 +608,11 @@ void SetOutputFormat(Service::Interface* self);
|
||||||
* 0: 0x00280040
|
* 0: 0x00280040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SynchronizeVsyncTiming(Service::Interface* self);
|
void SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns calibration data relating the outside cameras to eachother, for use in AR applications.
|
* Returns calibration data relating the outside cameras to each other, for use in AR
|
||||||
|
* applications.
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x002B0000
|
* 0: 0x002B0000
|
||||||
|
@ -593,9 +621,9 @@ void SynchronizeVsyncTiming(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* 2-17: `StereoCameraCalibrationData` structure with calibration values
|
* 2-17: `StereoCameraCalibrationData` structure with calibration values
|
||||||
*/
|
*/
|
||||||
void GetStereoCameraCalibrationData(Service::Interface* self);
|
void GetStereoCameraCalibrationData(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch-configures context-free settings.
|
* Batch-configures context-free settings.
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -606,9 +634,9 @@ void GetStereoCameraCalibrationData(Service::Interface* self);
|
||||||
* 0: 0x00330040
|
* 0: 0x00330040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetPackageParameterWithoutContext(Service::Interface* self);
|
void SetPackageParameterWithoutContext(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch-configures context-related settings with preset resolution parameters.
|
* Batch-configures context-related settings with preset resolution parameters.
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -619,9 +647,9 @@ void SetPackageParameterWithoutContext(Service::Interface* self);
|
||||||
* 0: 0x00340040
|
* 0: 0x00340040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetPackageParameterWithContext(Service::Interface* self);
|
void SetPackageParameterWithContext(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch-configures context-related settings with custom resolution parameters
|
* Batch-configures context-related settings with custom resolution parameters
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -632,9 +660,9 @@ void SetPackageParameterWithContext(Service::Interface* self);
|
||||||
* 0: 0x00350040
|
* 0: 0x00350040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void SetPackageParameterWithContextDetail(Service::Interface* self);
|
void SetPackageParameterWithContextDetail(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown
|
* Unknown
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00360000
|
* 0: 0x00360000
|
||||||
|
@ -643,9 +671,9 @@ void SetPackageParameterWithContextDetail(Service::Interface* self);
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
* 2: ?
|
* 2: ?
|
||||||
*/
|
*/
|
||||||
void GetSuitableY2rStandardCoefficient(Service::Interface* self);
|
void GetSuitableY2rStandardCoefficient(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown
|
* Unknown
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00380040
|
* 0: 0x00380040
|
||||||
|
@ -654,9 +682,9 @@ void GetSuitableY2rStandardCoefficient(Service::Interface* self);
|
||||||
* 0: 0x00380040
|
* 0: 0x00380040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void PlayShutterSound(Service::Interface* self);
|
void PlayShutterSound(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the camera driver. Must be called before using other functions.
|
* Initializes the camera driver. Must be called before using other functions.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x00390000
|
* 0: 0x00390000
|
||||||
|
@ -664,9 +692,9 @@ void PlayShutterSound(Service::Interface* self);
|
||||||
* 0: 0x00390040
|
* 0: 0x00390040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void DriverInitialize(Service::Interface* self);
|
void DriverInitialize(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuts down the camera driver.
|
* Shuts down the camera driver.
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x003A0000
|
* 0: 0x003A0000
|
||||||
|
@ -674,13 +702,81 @@ void DriverInitialize(Service::Interface* self);
|
||||||
* 0: 0x003A0040
|
* 0: 0x003A0040
|
||||||
* 1: ResultCode
|
* 1: ResultCode
|
||||||
*/
|
*/
|
||||||
void DriverFinalize(Service::Interface* self);
|
void DriverFinalize(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/// Initialize CAM service(s)
|
private:
|
||||||
void Init();
|
std::shared_ptr<Module> cam;
|
||||||
|
};
|
||||||
|
|
||||||
/// Shutdown CAM service(s)
|
private:
|
||||||
void Shutdown();
|
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 <typename PackageParameterType>
|
||||||
|
ResultCode SetPackageParameter(const PackageParameterType& package);
|
||||||
|
|
||||||
|
struct ContextConfig {
|
||||||
|
Flip flip;
|
||||||
|
Effect effect;
|
||||||
|
OutputFormat format;
|
||||||
|
Resolution resolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CameraConfig {
|
||||||
|
std::unique_ptr<Camera::CameraInterface> impl;
|
||||||
|
std::array<ContextConfig, 2> 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<Kernel::Event> completion_event;
|
||||||
|
Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event;
|
||||||
|
Kernel::SharedPtr<Kernel::Event> vsync_interrupt_event;
|
||||||
|
|
||||||
|
std::future<std::vector<u16>> 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<CameraConfig, NumCameras> cameras;
|
||||||
|
std::array<PortConfig, 2> ports;
|
||||||
|
CoreTiming::EventType* completion_event_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
} // namespace Service
|
} // namespace Service
|
||||||
|
|
|
@ -2,16 +2,81 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/hle/service/cam/cam.h"
|
||||||
#include "core/hle/service/cam/cam_c.h"
|
#include "core/hle/service/cam/cam_c.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
// Empty arrays are illegal -- commented out until an entry is added.
|
CAM_C::CAM_C(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "cam:c", 1) {
|
||||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
static const FunctionInfo functions[] = {
|
||||||
|
{0x00010040, &CAM_C::StartCapture, "StartCapture"},
|
||||||
CAM_C_Interface::CAM_C_Interface() {
|
{0x00020040, &CAM_C::StopCapture, "StopCapture"},
|
||||||
// Register(FunctionTable);
|
{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
|
} // namespace CAM
|
||||||
|
|
|
@ -4,18 +4,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/cam/cam.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
class CAM_C_Interface : public Service::Interface {
|
class CAM_C final : public Module::Interface {
|
||||||
public:
|
public:
|
||||||
CAM_C_Interface();
|
explicit CAM_C(std::shared_ptr<Module> cam);
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
|
||||||
return "cam:c";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -7,11 +7,10 @@
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
// Empty arrays are illegal -- commented out until an entry is added.
|
CAM_Q::CAM_Q() : ServiceFramework("cam:q", 1 /*TODO: find the true value*/) {
|
||||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
// Empty arrays are illegal -- commented out until an entry is added.
|
||||||
|
// static const FunctionInfo functions[] = {};
|
||||||
CAM_Q_Interface::CAM_Q_Interface() {
|
// RegisterHandlers(functions);
|
||||||
// Register(FunctionTable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -9,13 +9,9 @@
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
class CAM_Q_Interface : public Service::Interface {
|
class CAM_Q : public ServiceFramework<CAM_Q> {
|
||||||
public:
|
public:
|
||||||
CAM_Q_Interface();
|
CAM_Q();
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
|
||||||
return "cam:q";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -2,16 +2,81 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/hle/service/cam/cam.h"
|
||||||
#include "core/hle/service/cam/cam_s.h"
|
#include "core/hle/service/cam/cam_s.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
// Empty arrays are illegal -- commented out until an entry is added.
|
CAM_S::CAM_S(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "cam:s", 1) {
|
||||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
static const FunctionInfo functions[] = {
|
||||||
|
{0x00010040, &CAM_S::StartCapture, "StartCapture"},
|
||||||
CAM_S_Interface::CAM_S_Interface() {
|
{0x00020040, &CAM_S::StopCapture, "StopCapture"},
|
||||||
// Register(FunctionTable);
|
{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
|
} // namespace CAM
|
||||||
|
|
|
@ -4,18 +4,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/cam/cam.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
class CAM_S_Interface : public Service::Interface {
|
class CAM_S final : public Module::Interface {
|
||||||
public:
|
public:
|
||||||
CAM_S_Interface();
|
explicit CAM_S(std::shared_ptr<Module> cam);
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
|
||||||
return "cam:s";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -8,27 +8,28 @@
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
const Interface::FunctionInfo FunctionTable[] = {
|
CAM_U::CAM_U(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "cam:u", 1) {
|
||||||
{0x00010040, StartCapture, "StartCapture"},
|
static const FunctionInfo functions[] = {
|
||||||
{0x00020040, StopCapture, "StopCapture"},
|
{0x00010040, &CAM_U::StartCapture, "StartCapture"},
|
||||||
{0x00030040, IsBusy, "IsBusy"},
|
{0x00020040, &CAM_U::StopCapture, "StopCapture"},
|
||||||
{0x00040040, ClearBuffer, "ClearBuffer"},
|
{0x00030040, &CAM_U::IsBusy, "IsBusy"},
|
||||||
{0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"},
|
{0x00040040, &CAM_U::ClearBuffer, "ClearBuffer"},
|
||||||
{0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"},
|
{0x00050040, &CAM_U::GetVsyncInterruptEvent, "GetVsyncInterruptEvent"},
|
||||||
{0x00070102, SetReceiving, "SetReceiving"},
|
{0x00060040, &CAM_U::GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"},
|
||||||
{0x00080040, IsFinishedReceiving, "IsFinishedReceiving"},
|
{0x00070102, &CAM_U::SetReceiving, "SetReceiving"},
|
||||||
{0x00090100, SetTransferLines, "SetTransferLines"},
|
{0x00080040, &CAM_U::IsFinishedReceiving, "IsFinishedReceiving"},
|
||||||
{0x000A0080, GetMaxLines, "GetMaxLines"},
|
{0x00090100, &CAM_U::SetTransferLines, "SetTransferLines"},
|
||||||
{0x000B0100, SetTransferBytes, "SetTransferBytes"},
|
{0x000A0080, &CAM_U::GetMaxLines, "GetMaxLines"},
|
||||||
{0x000C0040, GetTransferBytes, "GetTransferBytes"},
|
{0x000B0100, &CAM_U::SetTransferBytes, "SetTransferBytes"},
|
||||||
{0x000D0080, GetMaxBytes, "GetMaxBytes"},
|
{0x000C0040, &CAM_U::GetTransferBytes, "GetTransferBytes"},
|
||||||
{0x000E0080, SetTrimming, "SetTrimming"},
|
{0x000D0080, &CAM_U::GetMaxBytes, "GetMaxBytes"},
|
||||||
{0x000F0040, IsTrimming, "IsTrimming"},
|
{0x000E0080, &CAM_U::SetTrimming, "SetTrimming"},
|
||||||
{0x00100140, SetTrimmingParams, "SetTrimmingParams"},
|
{0x000F0040, &CAM_U::IsTrimming, "IsTrimming"},
|
||||||
{0x00110040, GetTrimmingParams, "GetTrimmingParams"},
|
{0x00100140, &CAM_U::SetTrimmingParams, "SetTrimmingParams"},
|
||||||
{0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"},
|
{0x00110040, &CAM_U::GetTrimmingParams, "GetTrimmingParams"},
|
||||||
{0x00130040, Activate, "Activate"},
|
{0x00120140, &CAM_U::SetTrimmingParamsCenter, "SetTrimmingParamsCenter"},
|
||||||
{0x00140080, SwitchContext, "SwitchContext"},
|
{0x00130040, &CAM_U::Activate, "Activate"},
|
||||||
|
{0x00140080, &CAM_U::SwitchContext, "SwitchContext"},
|
||||||
{0x00150080, nullptr, "SetExposure"},
|
{0x00150080, nullptr, "SetExposure"},
|
||||||
{0x00160080, nullptr, "SetWhiteBalance"},
|
{0x00160080, nullptr, "SetWhiteBalance"},
|
||||||
{0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"},
|
{0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"},
|
||||||
|
@ -37,21 +38,21 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x001A0040, nullptr, "IsAutoExposure"},
|
{0x001A0040, nullptr, "IsAutoExposure"},
|
||||||
{0x001B0080, nullptr, "SetAutoWhiteBalance"},
|
{0x001B0080, nullptr, "SetAutoWhiteBalance"},
|
||||||
{0x001C0040, nullptr, "IsAutoWhiteBalance"},
|
{0x001C0040, nullptr, "IsAutoWhiteBalance"},
|
||||||
{0x001D00C0, FlipImage, "FlipImage"},
|
{0x001D00C0, &CAM_U::FlipImage, "FlipImage"},
|
||||||
{0x001E0200, SetDetailSize, "SetDetailSize"},
|
{0x001E0200, &CAM_U::SetDetailSize, "SetDetailSize"},
|
||||||
{0x001F00C0, SetSize, "SetSize"},
|
{0x001F00C0, &CAM_U::SetSize, "SetSize"},
|
||||||
{0x00200080, SetFrameRate, "SetFrameRate"},
|
{0x00200080, &CAM_U::SetFrameRate, "SetFrameRate"},
|
||||||
{0x00210080, nullptr, "SetPhotoMode"},
|
{0x00210080, nullptr, "SetPhotoMode"},
|
||||||
{0x002200C0, SetEffect, "SetEffect"},
|
{0x002200C0, &CAM_U::SetEffect, "SetEffect"},
|
||||||
{0x00230080, nullptr, "SetContrast"},
|
{0x00230080, nullptr, "SetContrast"},
|
||||||
{0x00240080, nullptr, "SetLensCorrection"},
|
{0x00240080, nullptr, "SetLensCorrection"},
|
||||||
{0x002500C0, SetOutputFormat, "SetOutputFormat"},
|
{0x002500C0, &CAM_U::SetOutputFormat, "SetOutputFormat"},
|
||||||
{0x00260140, nullptr, "SetAutoExposureWindow"},
|
{0x00260140, nullptr, "SetAutoExposureWindow"},
|
||||||
{0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
|
{0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
|
||||||
{0x00280080, nullptr, "SetNoiseFilter"},
|
{0x00280080, nullptr, "SetNoiseFilter"},
|
||||||
{0x00290080, SynchronizeVsyncTiming, "SynchronizeVsyncTiming"},
|
{0x00290080, &CAM_U::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"},
|
||||||
{0x002A0080, nullptr, "GetLatestVsyncTiming"},
|
{0x002A0080, nullptr, "GetLatestVsyncTiming"},
|
||||||
{0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
|
{0x002B0000, &CAM_U::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
|
||||||
{0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
|
{0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
|
||||||
{0x002D00C0, nullptr, "WriteRegisterI2c"},
|
{0x002D00C0, nullptr, "WriteRegisterI2c"},
|
||||||
{0x002E00C0, nullptr, "WriteMcuVariableI2c"},
|
{0x002E00C0, nullptr, "WriteMcuVariableI2c"},
|
||||||
|
@ -59,22 +60,23 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00300080, nullptr, "ReadMcuVariableI2cExclusive"},
|
{0x00300080, nullptr, "ReadMcuVariableI2cExclusive"},
|
||||||
{0x00310180, nullptr, "SetImageQualityCalibrationData"},
|
{0x00310180, nullptr, "SetImageQualityCalibrationData"},
|
||||||
{0x00320000, nullptr, "GetImageQualityCalibrationData"},
|
{0x00320000, nullptr, "GetImageQualityCalibrationData"},
|
||||||
{0x003302C0, SetPackageParameterWithoutContext, "SetPackageParameterWithoutContext"},
|
{0x003302C0, &CAM_U::SetPackageParameterWithoutContext,
|
||||||
{0x00340140, SetPackageParameterWithContext, "SetPackageParameterWithContext"},
|
"SetPackageParameterWithoutContext"},
|
||||||
{0x003501C0, SetPackageParameterWithContextDetail, "SetPackageParameterWithContextDetail"},
|
{0x00340140, &CAM_U::SetPackageParameterWithContext, "SetPackageParameterWithContext"},
|
||||||
{0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"},
|
{0x003501C0, &CAM_U::SetPackageParameterWithContextDetail,
|
||||||
|
"SetPackageParameterWithContextDetail"},
|
||||||
|
{0x00360000, &CAM_U::GetSuitableY2rStandardCoefficient,
|
||||||
|
"GetSuitableY2rStandardCoefficient"},
|
||||||
{0x00370202, nullptr, "PlayShutterSoundWithWave"},
|
{0x00370202, nullptr, "PlayShutterSoundWithWave"},
|
||||||
{0x00380040, PlayShutterSound, "PlayShutterSound"},
|
{0x00380040, &CAM_U::PlayShutterSound, "PlayShutterSound"},
|
||||||
{0x00390000, DriverInitialize, "DriverInitialize"},
|
{0x00390000, &CAM_U::DriverInitialize, "DriverInitialize"},
|
||||||
{0x003A0000, DriverFinalize, "DriverFinalize"},
|
{0x003A0000, &CAM_U::DriverFinalize, "DriverFinalize"},
|
||||||
{0x003B0000, nullptr, "GetActivatedCamera"},
|
{0x003B0000, nullptr, "GetActivatedCamera"},
|
||||||
{0x003C0000, nullptr, "GetSleepCamera"},
|
{0x003C0000, nullptr, "GetSleepCamera"},
|
||||||
{0x003D0040, nullptr, "SetSleepCamera"},
|
{0x003D0040, nullptr, "SetSleepCamera"},
|
||||||
{0x003E0040, nullptr, "SetBrightnessSynchronization"},
|
{0x003E0040, nullptr, "SetBrightnessSynchronization"},
|
||||||
};
|
};
|
||||||
|
RegisterHandlers(functions);
|
||||||
CAM_U_Interface::CAM_U_Interface() {
|
|
||||||
Register(FunctionTable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -4,18 +4,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/cam/cam.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CAM {
|
namespace CAM {
|
||||||
|
|
||||||
class CAM_U_Interface : public Service::Interface {
|
class CAM_U final : public Module::Interface {
|
||||||
public:
|
public:
|
||||||
CAM_U_Interface();
|
explicit CAM_U(std::shared_ptr<Module> cam);
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
|
||||||
return "cam:u";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CAM
|
} // namespace CAM
|
||||||
|
|
|
@ -269,7 +269,7 @@ void Init() {
|
||||||
AM::Init();
|
AM::Init();
|
||||||
APT::Init();
|
APT::Init();
|
||||||
BOSS::Init();
|
BOSS::Init();
|
||||||
CAM::Init();
|
CAM::InstallInterfaces(*SM::g_service_manager);
|
||||||
CECD::Init();
|
CECD::Init();
|
||||||
CFG::Init();
|
CFG::Init();
|
||||||
DLP::Init();
|
DLP::Init();
|
||||||
|
@ -312,7 +312,6 @@ void Shutdown() {
|
||||||
DLP::Shutdown();
|
DLP::Shutdown();
|
||||||
CFG::Shutdown();
|
CFG::Shutdown();
|
||||||
CECD::Shutdown();
|
CECD::Shutdown();
|
||||||
CAM::Shutdown();
|
|
||||||
BOSS::Shutdown();
|
BOSS::Shutdown();
|
||||||
APT::Shutdown();
|
APT::Shutdown();
|
||||||
AM::Shutdown();
|
AM::Shutdown();
|
||||||
|
|
Reference in New Issue