citra-emu
/
citra-canary
Archived
1
0
Fork 0

cam: use IPCHelper

This commit is contained in:
wwylele 2017-05-24 12:45:36 +03:00
parent c291db72e7
commit 924292f2cc
1 changed files with 234 additions and 274 deletions

View File

@ -55,7 +55,7 @@ struct PortConfig {
u16 x1; // x-coordinate of ending position for trimming u16 x1; // x-coordinate of ending position for trimming
u16 y1; // y-coordinate of ending position for trimming u16 y1; // y-coordinate of ending position for trimming
u32 transfer_bytes; u16 transfer_bytes;
Kernel::SharedPtr<Kernel::Event> completion_event; Kernel::SharedPtr<Kernel::Event> completion_event;
Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event; Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event;
@ -244,9 +244,10 @@ using CameraSet = CommandParamBitSet<3>;
} // namespace } // namespace
void StartCapture(Service::Interface* self) { void StartCapture(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); 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) {
@ -267,21 +268,20 @@ void StartCapture(Service::Interface* self) {
LOG_WARNING(Service_CAM, "port %u already started", i); LOG_WARNING(Service_CAM, "port %u already started", i);
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
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 StopCapture(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); 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) {
@ -293,21 +293,20 @@ void StopCapture(Service::Interface* self) {
LOG_WARNING(Service_CAM, "port %u already stopped", i); LOG_WARNING(Service_CAM, "port %u already stopped", i);
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0);
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 IsBusy(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (port_select.IsValid()) { if (port_select.IsValid()) {
bool is_busy = true; bool is_busy = true;
@ -315,80 +314,74 @@ void IsBusy(Service::Interface* self) {
for (int i : port_select) { for (int i : port_select) {
is_busy &= ports[i].is_busy; is_busy &= ports[i].is_busy;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = is_busy ? 1 : 0; rb.Push(is_busy);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
} }
cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0);
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 ClearBuffer(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
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 GetVsyncInterruptEvent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]);
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();
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = IPC::CopyHandleDesc(); rb.PushCopyHandles(
cmd_buff[3] = Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom(); Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom());
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
cmd_buff[2] = IPC::CopyHandleDesc(); rb.PushCopyHandles(0);
cmd_buff[2] = 0;
} }
cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2);
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 GetBufferErrorInterruptEvent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]);
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();
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = IPC::CopyHandleDesc(); rb.PushCopyHandles(
cmd_buff[3] = Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom());
Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom();
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
cmd_buff[2] = IPC::CopyHandleDesc(); rb.PushCopyHandles(0);
cmd_buff[2] = 0;
} }
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 SetReceiving(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2);
const VAddr dest = rp.Pop<u32>();
const VAddr dest = cmd_buff[1]; const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[2]); const u32 image_size = rp.Pop<u32>();
const u32 image_size = cmd_buff[3]; const u16 trans_unit = rp.Pop<u16>();
const u32 trans_unit = cmd_buff[4] & 0xFFFF; rp.PopHandle(); // Handle to destination process. not used
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 = ports[port_id];
@ -403,149 +396,143 @@ void SetReceiving(Service::Interface* self) {
port.is_pending_receiving = true; port.is_pending_receiving = true;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = IPC::CopyHandleDesc(); rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).MoveFrom());
cmd_buff[3] = Kernel::g_handle_table.Create(port.completion_event).MoveFrom();
} else { } else {
LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); rb.Push(ERROR_INVALID_ENUM_VALUE);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.PushCopyHandles(0);
} }
cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2);
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 IsFinishedReceiving(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]);
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();
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = (ports[port].is_receiving || ports[port].is_pending_receiving) ? 0 : 1; rb.Push(ports[port].is_receiving || ports[port].is_pending_receiving);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
} }
cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
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 SetTransferLines(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); const u16 transfer_lines = rp.Pop<u16>();
const u32 transfer_lines = cmd_buff[2] & 0xFFFF; const u16 width = rp.Pop<u16>();
const u32 width = cmd_buff[3] & 0xFFFF; const u16 height = rp.Pop<u16>();
const u32 height = cmd_buff[4] & 0xFFFF;
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; ports[i].transfer_bytes = transfer_lines * width * 2;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u", LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u",
port_select.m_val, transfer_lines, width, height); port_select.m_val, transfer_lines, width, height);
} }
void GetMaxLines(Service::Interface* self) { void GetMaxLines(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0);
const u16 width = rp.Pop<u16>();
const u16 height = rp.Pop<u16>();
const u32 width = cmd_buff[1] & 0xFFFF; IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
const u32 height = cmd_buff[2] & 0xFFFF;
// Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
constexpr u32 MIN_TRANSFER_UNIT = 256; constexpr u32 MIN_TRANSFER_UNIT = 256;
constexpr u32 MAX_BUFFER_SIZE = 2560; constexpr u32 MAX_BUFFER_SIZE = 2560;
if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; rb.Push(ERROR_OUT_OF_RANGE);
rb.Skip(1, false);
} else { } else {
u32 lines = MAX_BUFFER_SIZE / width; u32 lines = MAX_BUFFER_SIZE / width;
if (lines > height) { if (lines > height) {
lines = height; lines = height;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; ResultCode result = RESULT_SUCCESS;
while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) { while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) {
--lines; --lines;
if (lines == 0) { if (lines == 0) {
cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; result = ERROR_OUT_OF_RANGE;
break; break;
} }
} }
cmd_buff[2] = lines; rb.Push(result);
rb.Push(lines);
} }
cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
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 SetTransferBytes(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); const u16 transfer_bytes = rp.Pop<u16>();
const u32 transfer_bytes = cmd_buff[2] & 0xFFFF; const u16 width = rp.Pop<u16>();
const u32 width = cmd_buff[3] & 0xFFFF; const u16 height = rp.Pop<u16>();
const u32 height = cmd_buff[4] & 0xFFFF;
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; ports[i].transfer_bytes = transfer_bytes;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0);
LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u", LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u",
port_select.m_val, transfer_bytes, width, height); port_select.m_val, transfer_bytes, width, height);
} }
void GetTransferBytes(Service::Interface* self) { void GetTransferBytes(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]);
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();
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS.raw);
cmd_buff[2] = ports[port].transfer_bytes; rb.Push(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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
} }
cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
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 GetMaxBytes(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0);
const u16 width = rp.Pop<u16>();
const u16 height = rp.Pop<u16>();
const u32 width = cmd_buff[1] & 0xFFFF; IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
const u32 height = cmd_buff[2] & 0xFFFF;
// Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
constexpr u32 MIN_TRANSFER_UNIT = 256; constexpr u32 MIN_TRANSFER_UNIT = 256;
constexpr u32 MAX_BUFFER_SIZE = 2560; constexpr u32 MAX_BUFFER_SIZE = 2560;
if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; rb.Push(ERROR_OUT_OF_RANGE);
rb.Skip(1, false);
} else { } else {
u32 bytes = MAX_BUFFER_SIZE; u32 bytes = MAX_BUFFER_SIZE;
@ -553,63 +540,59 @@ void GetMaxBytes(Service::Interface* self) {
bytes -= MIN_TRANSFER_UNIT; bytes -= MIN_TRANSFER_UNIT;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = bytes; rb.Push(bytes);
} }
cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0);
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 SetTrimming(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); const bool trim = rp.Pop<bool>();
const bool trim = (cmd_buff[2] & 0xFF) != 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; ports[i].is_trimming = trim;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0);
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 IsTrimming(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]);
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();
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = ports[port].is_trimming; rb.Push(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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
} }
cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
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 SetTrimmingParams(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); const u16 x0 = rp.Pop<u16>();
const u16 x0 = static_cast<u16>(cmd_buff[2] & 0xFFFF); const u16 y0 = rp.Pop<u16>();
const u16 y0 = static_cast<u16>(cmd_buff[3] & 0xFFFF); const u16 x1 = rp.Pop<u16>();
const u16 x1 = static_cast<u16>(cmd_buff[4] & 0xFFFF); const u16 y1 = rp.Pop<u16>();
const u16 y1 = static_cast<u16>(cmd_buff[5] & 0xFFFF);
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; ports[i].x0 = x0;
@ -617,49 +600,46 @@ void SetTrimmingParams(Service::Interface* self) {
ports[i].x1 = x1; ports[i].x1 = x1;
ports[i].y1 = y1; ports[i].y1 = y1;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val, LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val,
x0, y0, x1, y1); x0, y0, x1, y1);
} }
void GetTrimmingParams(Service::Interface* self) { void GetTrimmingParams(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]);
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();
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = ports[port].x0; rb.Push(ports[port].x0);
cmd_buff[3] = ports[port].y0; rb.Push(ports[port].y0);
cmd_buff[4] = ports[port].x1; rb.Push(ports[port].x1);
cmd_buff[5] = ports[port].y1; rb.Push(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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(4, false);
} }
cmd_buff[0] = IPC::MakeHeader(0x11, 5, 0);
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 SetTrimmingParamsCenter(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0);
const PortSet port_select(rp.Pop<u32>());
const PortSet port_select(cmd_buff[1]); const u16 trim_w = rp.Pop<u16>();
const u16 trim_w = static_cast<u16>(cmd_buff[2] & 0xFFFF); const u16 trim_h = rp.Pop<u16>();
const u16 trim_h = static_cast<u16>(cmd_buff[3] & 0xFFFF); const u16 cam_w = rp.Pop<u16>();
const u16 cam_w = static_cast<u16>(cmd_buff[4] & 0xFFFF); const u16 cam_h = rp.Pop<u16>();
const u16 cam_h = static_cast<u16>(cmd_buff[5] & 0xFFFF);
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; ports[i].x0 = (cam_w - trim_w) / 2;
@ -667,23 +647,21 @@ void SetTrimmingParamsCenter(Service::Interface* self) {
ports[i].x1 = ports[i].x0 + trim_w; ports[i].x1 = ports[i].x0 + trim_w;
ports[i].y1 = ports[i].y0 + trim_h; ports[i].y1 = ports[i].y0 + trim_h;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} 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);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u", LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u",
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 Activate(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]);
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) {
@ -694,10 +672,10 @@ void Activate(Service::Interface* self) {
} }
ports[i].is_active = false; ports[i].is_active = false;
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else if (camera_select[0] && camera_select[1]) { } else if (camera_select[0] && camera_select[1]) {
LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated"); LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated");
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} else { } else {
if (camera_select[0]) { if (camera_select[0]) {
ActivatePort(0, 0); ActivatePort(0, 0);
@ -708,24 +686,22 @@ void Activate(Service::Interface* self) {
if (camera_select[2]) { if (camera_select[2]) {
ActivatePort(1, 2); ActivatePort(1, 2);
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} }
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
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 SwitchContext(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]); const ContextSet context_select(rp.Pop<u32>());
const ContextSet context_select(cmd_buff[2]);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -736,26 +712,24 @@ void SwitchContext(Service::Interface* self) {
cameras[camera].impl->SetFormat(context_config.format); cameras[camera].impl->SetFormat(context_config.format);
cameras[camera].impl->SetResolution(context_config.resolution); cameras[camera].impl->SetResolution(context_config.resolution);
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0);
LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val, LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
} }
void FlipImage(Service::Interface* self) { void FlipImage(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]); const Flip flip = static_cast<Flip>(rp.Pop<u8>());
const Flip flip = static_cast<Flip>(cmd_buff[2] & 0xFF); const ContextSet context_select(rp.Pop<u32>());
const ContextSet context_select(cmd_buff[3]);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -765,32 +739,30 @@ void FlipImage(Service::Interface* self) {
} }
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0);
LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u", LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u",
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 SetDetailSize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]);
Resolution resolution; Resolution resolution;
resolution.width = static_cast<u16>(cmd_buff[2] & 0xFFFF); resolution.width = rp.Pop<u16>();
resolution.height = static_cast<u16>(cmd_buff[3] & 0xFFFF); resolution.height = rp.Pop<u16>();
resolution.crop_x0 = static_cast<u16>(cmd_buff[4] & 0xFFFF); resolution.crop_x0 = rp.Pop<u16>();
resolution.crop_y0 = static_cast<u16>(cmd_buff[5] & 0xFFFF); resolution.crop_y0 = rp.Pop<u16>();
resolution.crop_x1 = static_cast<u16>(cmd_buff[6] & 0xFFFF); resolution.crop_x1 = rp.Pop<u16>();
resolution.crop_y1 = static_cast<u16>(cmd_buff[7] & 0xFFFF); resolution.crop_y1 = rp.Pop<u16>();
const ContextSet context_select(cmd_buff[8]); const ContextSet context_select(rp.Pop<u32>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -800,15 +772,13 @@ void SetDetailSize(Service::Interface* self) {
} }
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0);
LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, " LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, "
"crop_x1=%u, crop_y1=%u, context_select=%u", "crop_x1=%u, crop_y1=%u, context_select=%u",
camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0, camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0,
@ -816,12 +786,12 @@ void SetDetailSize(Service::Interface* self) {
} }
void SetSize(Service::Interface* self) { void SetSize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]); const u8 size = rp.Pop<u8>();
const u32 size = cmd_buff[2] & 0xFF; const ContextSet context_select(rp.Pop<u32>());
const ContextSet context_select(cmd_buff[3]);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -831,49 +801,45 @@ void SetSize(Service::Interface* self) {
} }
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0);
LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u", LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u",
camera_select.m_val, size, context_select.m_val); camera_select.m_val, size, context_select.m_val);
} }
void SetFrameRate(Service::Interface* self) { void SetFrameRate(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]); const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
const FrameRate frame_rate = static_cast<FrameRate>(cmd_buff[2] & 0xFF);
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; 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
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d", LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d",
camera_select.m_val, static_cast<int>(frame_rate)); camera_select.m_val, static_cast<int>(frame_rate));
} }
void SetEffect(Service::Interface* self) { void SetEffect(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]); const Effect effect = static_cast<Effect>(rp.Pop<u8>());
const Effect effect = static_cast<Effect>(cmd_buff[2] & 0xFF); const ContextSet context_select(rp.Pop<u32>());
const ContextSet context_select(cmd_buff[3]);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -883,26 +849,24 @@ void SetEffect(Service::Interface* self) {
} }
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0);
LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u", LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u",
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 SetOutputFormat(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0);
const CameraSet camera_select(rp.Pop<u32>());
const CameraSet camera_select(cmd_buff[1]); const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
const OutputFormat format = static_cast<OutputFormat>(cmd_buff[2] & 0xFF); const ContextSet context_select(rp.Pop<u32>());
const ContextSet context_select(cmd_buff[3]);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -912,34 +876,32 @@ void SetOutputFormat(Service::Interface* self) {
} }
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
context_select.m_val); context_select.m_val);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(0x25, 1, 0);
LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u", LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u",
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 SynchronizeVsyncTiming(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0);
const u8 camera_select1 = rp.Pop<u8>();
const u8 camera_select2 = rp.Pop<u8>();
const u32 camera_select1 = cmd_buff[1] & 0xFF; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
const u32 camera_select2 = cmd_buff[2] & 0xFF; rb.Push(RESULT_SUCCESS);
cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw;
LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u", LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u",
camera_select1, camera_select2); camera_select1, camera_select2);
} }
void GetStereoCameraCalibrationData(Service::Interface* self) { void GetStereoCameraCalibrationData(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestBuilder rb =
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.
@ -958,35 +920,37 @@ void GetStereoCameraCalibrationData(Service::Interface* self) {
data.imageWidth = 640; data.imageWidth = 640;
data.imageHeight = 480; data.imageHeight = 480;
cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0); rb.Push(RESULT_SUCCESS);
cmd_buff[1] = RESULT_SUCCESS.raw; rb.PushRaw(data);
memcpy(&cmd_buff[2], &data, sizeof(data));
LOG_TRACE(Service_CAM, "called"); LOG_TRACE(Service_CAM, "called");
} }
void SetPackageParameterWithoutContext(Service::Interface* self) { void SetPackageParameterWithoutContext(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0);
PackageParameterWithoutContext package; PackageParameterWithoutContext package;
std::memcpy(&package, cmd_buff + 1, sizeof(package)); rp.PopRaw(package);
rp.Skip(4, false);
cmd_buff[0] = IPC::MakeHeader(0x33, 1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_CAM, "(STUBBED) called"); LOG_WARNING(Service_CAM, "(STUBBED) called");
} }
template <typename PackageParameterType, int command_id> template <typename PackageParameterType, int command_id, int param_length>
static void SetPackageParameter() { static void SetPackageParameter() {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), command_id, param_length, 0);
PackageParameterType package; PackageParameterType package;
std::memcpy(&package, cmd_buff + 1, sizeof(package)); rp.PopRaw(package);
rp.Skip(param_length - (sizeof(PackageParameterType) + 3) / 4, false);
const CameraSet camera_select(static_cast<u32>(package.camera_select)); const CameraSet camera_select(static_cast<u32>(package.camera_select));
const ContextSet context_select(static_cast<u32>(package.context_select)); const ContextSet context_select(static_cast<u32>(package.context_select));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) { if (camera_select.IsValid() && context_select.IsValid()) {
for (int camera_id : camera_select) { for (int camera_id : camera_select) {
CameraConfig& camera = cameras[camera_id]; CameraConfig& camera = cameras[camera_id];
@ -1002,15 +966,13 @@ static void SetPackageParameter() {
} }
} }
} }
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
} else { } else {
LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select, LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select,
package.context_select); package.context_select);
cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; rb.Push(ERROR_INVALID_ENUM_VALUE);
} }
cmd_buff[0] = IPC::MakeHeader(command_id, 1, 0);
LOG_DEBUG(Service_CAM, "called"); LOG_DEBUG(Service_CAM, "called");
} }
@ -1019,36 +981,35 @@ Resolution PackageParameterWithContext::GetResolution() {
} }
void SetPackageParameterWithContext(Service::Interface* self) { void SetPackageParameterWithContext(Service::Interface* self) {
SetPackageParameter<PackageParameterWithContext, 0x34>(); SetPackageParameter<PackageParameterWithContext, 0x34, 5>();
} }
void SetPackageParameterWithContextDetail(Service::Interface* self) { void SetPackageParameterWithContextDetail(Service::Interface* self) {
SetPackageParameter<PackageParameterWithContextDetail, 0x35>(); SetPackageParameter<PackageParameterWithContextDetail, 0x35, 7>();
} }
void GetSuitableY2rStandardCoefficient(Service::Interface* self) { void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestBuilder rb =
IPC::RequestParser(Kernel::GetCommandBuffer(), 0x36, 0, 0).MakeBuilder(2, 0);
cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0); rb.Push(RESULT_SUCCESS);
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push<u32>(0);
cmd_buff[2] = 0;
LOG_WARNING(Service_CAM, "(STUBBED) called"); LOG_WARNING(Service_CAM, "(STUBBED) called");
} }
void PlayShutterSound(Service::Interface* self) { void PlayShutterSound(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0);
u8 sound_id = rp.Pop<u8>();
u8 sound_id = cmd_buff[1] & 0xFF; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
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); LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id);
} }
void DriverInitialize(Service::Interface* self) { void DriverInitialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestBuilder rb =
IPC::RequestParser(Kernel::GetCommandBuffer(), 0x39, 0, 0).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 = cameras[camera_id];
@ -1074,14 +1035,14 @@ void DriverInitialize(Service::Interface* self) {
port.Clear(); port.Clear();
} }
cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0); rb.Push(RESULT_SUCCESS);
cmd_buff[1] = RESULT_SUCCESS.raw;
LOG_DEBUG(Service_CAM, "called"); LOG_DEBUG(Service_CAM, "called");
} }
void DriverFinalize(Service::Interface* self) { void DriverFinalize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestBuilder rb =
IPC::RequestParser(Kernel::GetCommandBuffer(), 0x3A, 0, 0).MakeBuilder(1, 0);
CancelReceiving(0); CancelReceiving(0);
CancelReceiving(1); CancelReceiving(1);
@ -1090,8 +1051,7 @@ void DriverFinalize(Service::Interface* self) {
camera.impl = nullptr; camera.impl = nullptr;
} }
cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0); rb.Push(RESULT_SUCCESS);
cmd_buff[1] = RESULT_SUCCESS.raw;
LOG_DEBUG(Service_CAM, "called"); LOG_DEBUG(Service_CAM, "called");
} }