|
|
|
@ -4,16 +4,287 @@ |
|
|
|
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
|
|
|
|
#include "core/hle/service/service.h"
|
|
|
|
#include "core/hle/kernel/event.h"
|
|
|
|
#include "core/hle/service/cam/cam.h"
|
|
|
|
#include "core/hle/service/cam/cam_c.h"
|
|
|
|
#include "core/hle/service/cam/cam_q.h"
|
|
|
|
#include "core/hle/service/cam/cam_s.h"
|
|
|
|
#include "core/hle/service/cam/cam_u.h"
|
|
|
|
#include "core/hle/service/service.h"
|
|
|
|
|
|
|
|
namespace Service { |
|
|
|
namespace CAM { |
|
|
|
|
|
|
|
static const u32 TRANSFER_BYTES = 5 * 1024; |
|
|
|
|
|
|
|
static Kernel::SharedPtr<Kernel::Event> completion_event_cam1; |
|
|
|
static Kernel::SharedPtr<Kernel::Event> completion_event_cam2; |
|
|
|
static Kernel::SharedPtr<Kernel::Event> interrupt_error_event; |
|
|
|
static Kernel::SharedPtr<Kernel::Event> vsync_interrupt_error_event; |
|
|
|
|
|
|
|
void StartCapture(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); |
|
|
|
} |
|
|
|
|
|
|
|
void StopCapture(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); |
|
|
|
} |
|
|
|
|
|
|
|
void GetVsyncInterruptEvent(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
cmd_buff[2] = IPC::MoveHandleDesc(); |
|
|
|
cmd_buff[3] = Kernel::g_handle_table.Create(vsync_interrupt_error_event).MoveFrom(); |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); |
|
|
|
} |
|
|
|
|
|
|
|
void GetBufferErrorInterruptEvent(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x6, 1, 2); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
cmd_buff[2] = IPC::MoveHandleDesc(); |
|
|
|
cmd_buff[3] = Kernel::g_handle_table.Create(interrupt_error_event).MoveFrom(); |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); |
|
|
|
} |
|
|
|
|
|
|
|
void SetReceiving(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
VAddr dest = cmd_buff[1]; |
|
|
|
u8 port = cmd_buff[2] & 0xFF; |
|
|
|
u32 image_size = cmd_buff[3]; |
|
|
|
u16 trans_unit = cmd_buff[4] & 0xFFFF; |
|
|
|
|
|
|
|
Kernel::Event* completion_event = (Port)port == Port::Cam2 ? |
|
|
|
completion_event_cam2.get() : completion_event_cam1.get(); |
|
|
|
|
|
|
|
completion_event->Signal(); |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
cmd_buff[2] = IPC::MoveHandleDesc(); |
|
|
|
cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom(); |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, addr=0x%X, port=%d, image_size=%d, trans_unit=%d", |
|
|
|
dest, port, image_size, trans_unit); |
|
|
|
} |
|
|
|
|
|
|
|
void SetTransferLines(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
u16 transfer_lines = cmd_buff[2] & 0xFFFF; |
|
|
|
u16 width = cmd_buff[3] & 0xFFFF; |
|
|
|
u16 height = cmd_buff[4] & 0xFFFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, lines=%d, width=%d, height=%d", |
|
|
|
port, transfer_lines, width, height); |
|
|
|
} |
|
|
|
|
|
|
|
void GetMaxLines(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u16 width = cmd_buff[1] & 0xFFFF; |
|
|
|
u16 height = cmd_buff[2] & 0xFFFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
cmd_buff[2] = TRANSFER_BYTES / (2 * width); |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, width=%d, height=%d, lines = %d", |
|
|
|
width, height, cmd_buff[2]); |
|
|
|
} |
|
|
|
|
|
|
|
void GetTransferBytes(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
cmd_buff[2] = TRANSFER_BYTES; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); |
|
|
|
} |
|
|
|
|
|
|
|
void SetTrimming(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
bool trim = (cmd_buff[2] & 0xFF) != 0; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trim=%d", port, trim); |
|
|
|
} |
|
|
|
|
|
|
|
void SetTrimmingParamsCenter(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 port = cmd_buff[1] & 0xFF; |
|
|
|
s16 trimW = cmd_buff[2] & 0xFFFF; |
|
|
|
s16 trimH = cmd_buff[3] & 0xFFFF; |
|
|
|
s16 camW = cmd_buff[4] & 0xFFFF; |
|
|
|
s16 camH = cmd_buff[5] & 0xFFFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trimW=%d, trimH=%d, camW=%d, camH=%d", |
|
|
|
port, trimW, trimH, camW, camH); |
|
|
|
} |
|
|
|
|
|
|
|
void Activate(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 cam_select = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d", |
|
|
|
cam_select); |
|
|
|
} |
|
|
|
|
|
|
|
void FlipImage(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 cam_select = cmd_buff[1] & 0xFF; |
|
|
|
u8 flip = cmd_buff[2] & 0xFF; |
|
|
|
u8 context = cmd_buff[3] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, flip=%d, context=%d", |
|
|
|
cam_select, flip, context); |
|
|
|
} |
|
|
|
|
|
|
|
void SetSize(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 cam_select = cmd_buff[1] & 0xFF; |
|
|
|
u8 size = cmd_buff[2] & 0xFF; |
|
|
|
u8 context = cmd_buff[3] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, size=%d, context=%d", |
|
|
|
cam_select, size, context); |
|
|
|
} |
|
|
|
|
|
|
|
void SetFrameRate(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 cam_select = cmd_buff[1] & 0xFF; |
|
|
|
u8 frame_rate = cmd_buff[2] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, frame_rate=%d", |
|
|
|
cam_select, frame_rate); |
|
|
|
} |
|
|
|
|
|
|
|
void GetStereoCameraCalibrationData(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
// Default values taken from yuriks' 3DS. Valid data is required here or games using the
|
|
|
|
// calibration get stuck in an infinite CPU loop.
|
|
|
|
StereoCameraCalibrationData data = {}; |
|
|
|
data.isValidRotationXY = 0; |
|
|
|
data.scale = 1.001776f; |
|
|
|
data.rotationZ = 0.008322907f; |
|
|
|
data.translationX = -87.70484f; |
|
|
|
data.translationY = -7.640977f; |
|
|
|
data.rotationX = 0.0f; |
|
|
|
data.rotationY = 0.0f; |
|
|
|
data.angleOfViewRight = 64.66875f; |
|
|
|
data.angleOfViewLeft = 64.76067f; |
|
|
|
data.distanceToChart = 250.0f; |
|
|
|
data.distanceCameras = 35.0f; |
|
|
|
data.imageWidth = 640; |
|
|
|
data.imageHeight = 480; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
memcpy(&cmd_buff[2], &data, sizeof(data)); |
|
|
|
|
|
|
|
LOG_TRACE(Service_CAM, "called"); |
|
|
|
} |
|
|
|
|
|
|
|
void GetSuitableY2rStandardCoefficient(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
cmd_buff[2] = 0; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called"); |
|
|
|
} |
|
|
|
|
|
|
|
void PlayShutterSound(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
u8 sound_id = cmd_buff[1] & 0xFF; |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x38, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); |
|
|
|
} |
|
|
|
|
|
|
|
void DriverInitialize(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
completion_event_cam1->Clear(); |
|
|
|
completion_event_cam2->Clear(); |
|
|
|
interrupt_error_event->Clear(); |
|
|
|
vsync_interrupt_error_event->Clear(); |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called"); |
|
|
|
} |
|
|
|
|
|
|
|
void DriverFinalize(Service::Interface* self) { |
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0); |
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
LOG_WARNING(Service_CAM, "(STUBBED) called"); |
|
|
|
} |
|
|
|
|
|
|
|
void Init() { |
|
|
|
using namespace Kernel; |
|
|
|
|
|
|
|
@ -21,9 +292,18 @@ void Init() { |
|
|
|
AddService(new CAM_Q_Interface); |
|
|
|
AddService(new CAM_S_Interface); |
|
|
|
AddService(new CAM_U_Interface); |
|
|
|
|
|
|
|
completion_event_cam1 = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::completion_event_cam1"); |
|
|
|
completion_event_cam2 = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::completion_event_cam2"); |
|
|
|
interrupt_error_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::interrupt_error_event"); |
|
|
|
vsync_interrupt_error_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::vsync_interrupt_error_event"); |
|
|
|
} |
|
|
|
|
|
|
|
void Shutdown() { |
|
|
|
completion_event_cam1 = nullptr; |
|
|
|
completion_event_cam2 = nullptr; |
|
|
|
interrupt_error_event = nullptr; |
|
|
|
vsync_interrupt_error_event = nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace CAM
|
|
|
|
|