citra-emu
/
citra
Archived
1
0
Fork 0

cam: Ensure camera implementation is not null before using it (#7368)

* cam: Use PopEnum and update result names

* cam: Make sure impl is not null before using it
This commit is contained in:
GPUCode 2024-01-22 09:32:46 +02:00 committed by GitHub
parent 82294425e3
commit eddc4a029c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 108 additions and 75 deletions

View File

@ -10,7 +10,6 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/camera/factory.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/process.h"
@ -77,9 +76,9 @@ constexpr std::array<int, 13> LATENCY_BY_FRAME_RATE{{
33, // Rate_30_To_10
}};
const Result ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
constexpr Result ResultInvalidEnumValue(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
const Result ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM,
constexpr Result ResultOutOfRange(ErrorDescription::OutOfRange, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
void Module::PortConfig::Clear() {
@ -261,27 +260,32 @@ void Module::Interface::StartCapture(Kernel::HLERequestContext& ctx) {
if (port_select.IsValid()) {
for (int i : port_select) {
if (!cam->ports[i].is_busy) {
if (!cam->ports[i].is_active) {
auto& port = cam->ports[i];
if (port.is_busy) {
LOG_WARNING(Service_CAM, "port {} already started", i);
continue;
}
if (!port.is_active) {
// This doesn't return an error, but seems to put the camera in an undefined
// state
LOG_ERROR(Service_CAM, "port {} hasn't been activated", i);
} else {
cam->cameras[cam->ports[i].camera_id].impl->StartCapture();
cam->ports[i].is_busy = true;
if (cam->ports[i].is_pending_receiving) {
cam->ports[i].is_pending_receiving = false;
continue;
}
auto& camera = cam->cameras[port.camera_id];
if (!camera.impl) {
cam->LoadCameraImplementation(camera, port.camera_id);
}
camera.impl->StartCapture();
port.is_busy = true;
if (port.is_pending_receiving) {
port.is_pending_receiving = false;
cam->StartReceiving(i);
}
}
} else {
LOG_WARNING(Service_CAM, "port {} already started", i);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, port_select={}", port_select.m_val);
@ -306,7 +310,7 @@ void Module::Interface::StopCapture(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, port_select={}", port_select.m_val);
@ -328,7 +332,7 @@ void Module::Interface::IsBusy(Kernel::HLERequestContext& ctx) {
rb.Push(is_busy);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.Skip(1, false);
}
@ -356,7 +360,7 @@ void Module::Interface::GetVsyncInterruptEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(cam->ports[port].vsync_interrupt_event);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.PushCopyObjects<Kernel::Object>(nullptr);
}
@ -374,7 +378,7 @@ void Module::Interface::GetBufferErrorInterruptEvent(Kernel::HLERequestContext&
rb.PushCopyObjects(cam->ports[port].buffer_error_interrupt_event);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.PushCopyObjects<Kernel::Object>(nullptr);
}
@ -409,7 +413,7 @@ void Module::Interface::SetReceiving(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(port.completion_event);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.PushCopyObjects<Kernel::Object>(nullptr);
}
@ -429,7 +433,7 @@ void Module::Interface::IsFinishedReceiving(Kernel::HLERequestContext& ctx) {
rb.Push(!is_busy);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.Skip(1, false);
}
@ -451,7 +455,7 @@ void Module::Interface::SetTransferLines(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select={}, lines={}, width={}, height={}",
@ -469,7 +473,7 @@ void Module::Interface::GetMaxLines(Kernel::HLERequestContext& ctx) {
constexpr u32 MIN_TRANSFER_UNIT = 256;
constexpr u32 MAX_BUFFER_SIZE = 2560;
if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
rb.Push(ERROR_OUT_OF_RANGE);
rb.Push(ResultOutOfRange);
rb.Skip(1, false);
} else {
u32 lines = MAX_BUFFER_SIZE / width;
@ -480,7 +484,7 @@ void Module::Interface::GetMaxLines(Kernel::HLERequestContext& ctx) {
while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) {
--lines;
if (lines == 0) {
result = ERROR_OUT_OF_RANGE;
result = ResultOutOfRange;
break;
}
}
@ -506,7 +510,7 @@ void Module::Interface::SetTransferBytes(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_WARNING(Service_CAM, "(STUBBED)called, port_select={}, bytes={}, width={}, height={}",
@ -524,7 +528,7 @@ void Module::Interface::GetTransferBytes(Kernel::HLERequestContext& ctx) {
rb.Push(cam->ports[port].transfer_bytes);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.Skip(1, false);
}
@ -542,7 +546,7 @@ void Module::Interface::GetMaxBytes(Kernel::HLERequestContext& ctx) {
constexpr u32 MIN_TRANSFER_UNIT = 256;
constexpr u32 MAX_BUFFER_SIZE = 2560;
if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
rb.Push(ERROR_OUT_OF_RANGE);
rb.Push(ResultOutOfRange);
rb.Skip(1, false);
} else {
u32 bytes = MAX_BUFFER_SIZE;
@ -571,7 +575,7 @@ void Module::Interface::SetTrimming(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, port_select={}, trim={}", port_select.m_val, trim);
@ -588,7 +592,7 @@ void Module::Interface::IsTrimming(Kernel::HLERequestContext& ctx) {
rb.Push(cam->ports[port].is_trimming);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.Skip(1, false);
}
@ -614,7 +618,7 @@ void Module::Interface::SetTrimmingParams(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, port_select={}, x0={}, y0={}, x1={}, y1={}", port_select.m_val,
@ -635,7 +639,7 @@ void Module::Interface::GetTrimmingParams(Kernel::HLERequestContext& ctx) {
rb.Push(cam->ports[port].y1);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
rb.Skip(4, false);
}
@ -661,7 +665,7 @@ void Module::Interface::SetTrimmingParamsCenter(Kernel::HLERequestContext& ctx)
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, port_select={}, trim_w={}, trim_h={}, cam_w={}, cam_h={}",
@ -687,7 +691,7 @@ void Module::Interface::Activate(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else if (camera_select[0] && camera_select[1]) {
LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated");
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
} else {
if (camera_select[0]) {
cam->ActivatePort(0, 0);
@ -702,7 +706,7 @@ void Module::Interface::Activate(Kernel::HLERequestContext& ctx) {
}
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}", camera_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}", camera_select.m_val);
@ -728,7 +732,7 @@ void Module::Interface::SwitchContext(Kernel::HLERequestContext& ctx) {
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, context_select={}", camera_select.m_val,
@ -738,24 +742,29 @@ void Module::Interface::SwitchContext(Kernel::HLERequestContext& ctx) {
void Module::Interface::FlipImage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const Flip flip = static_cast<Flip>(rp.Pop<u8>());
const Flip flip = rp.PopEnum<Flip>();
const ContextSet context_select(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int camera : camera_select) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int context : context_select) {
cam->cameras[camera].contexts[context].flip = flip;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetFlip(flip);
camera.contexts[context].flip = flip;
if (camera.current_context != context) {
continue;
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetFlip(flip);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, flip={}, context_select={}",
@ -776,19 +785,24 @@ void Module::Interface::SetDetailSize(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int camera : camera_select) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int context : context_select) {
cam->cameras[camera].contexts[context].resolution = resolution;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetResolution(resolution);
camera.contexts[context].resolution = resolution;
if (camera.current_context != context) {
continue;
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetResolution(resolution);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM,
@ -806,19 +820,24 @@ void Module::Interface::SetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int camera : camera_select) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int context : context_select) {
cam->cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size];
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]);
camera.contexts[context].resolution = PRESET_RESOLUTION[size];
if (camera.current_context != context) {
continue;
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetResolution(PRESET_RESOLUTION[size]);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, size={}, context_select={}",
@ -828,18 +847,22 @@ void Module::Interface::SetSize(Kernel::HLERequestContext& ctx) {
void Module::Interface::SetFrameRate(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
const FrameRate frame_rate = rp.PopEnum<FrameRate>();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid()) {
for (int camera : camera_select) {
cam->cameras[camera].frame_rate = frame_rate;
cam->cameras[camera].impl->SetFrameRate(frame_rate);
for (int index : camera_select) {
auto& camera = cam->cameras[index];
camera.frame_rate = frame_rate;
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetFrameRate(frame_rate);
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}", camera_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select={}, frame_rate={}",
@ -849,24 +872,29 @@ void Module::Interface::SetFrameRate(Kernel::HLERequestContext& ctx) {
void Module::Interface::SetEffect(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const Effect effect = static_cast<Effect>(rp.Pop<u8>());
const Effect effect = rp.PopEnum<Effect>();
const ContextSet context_select(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int camera : camera_select) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int context : context_select) {
cam->cameras[camera].contexts[context].effect = effect;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetEffect(effect);
camera.contexts[context].effect = effect;
if (camera.current_context != context) {
continue;
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetEffect(effect);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, effect={}, context_select={}",
@ -876,24 +904,29 @@ void Module::Interface::SetEffect(Kernel::HLERequestContext& ctx) {
void Module::Interface::SetOutputFormat(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
const OutputFormat format = rp.PopEnum<OutputFormat>();
const ContextSet context_select(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int camera : camera_select) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int context : context_select) {
cam->cameras[camera].contexts[context].format = format;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetFormat(format);
camera.contexts[context].format = format;
if (camera.current_context != context) {
continue;
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetFormat(format);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Push(ResultInvalidEnumValue);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, format={}, context_select={}",
@ -919,7 +952,7 @@ void Module::Interface::GetLatestVsyncTiming(Kernel::HLERequestContext& ctx) {
if (!port_select.IsSingle() || count > MaxVsyncTimings) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(ERROR_OUT_OF_RANGE);
rb.Push(ResultOutOfRange);
rb.PushStaticBuffer({}, 0);
return;
}
@ -1003,7 +1036,7 @@ Result Module::SetPackageParameter(const PackageParameterType& package) {
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", package.camera_select,
package.context_select);
return ERROR_INVALID_ENUM_VALUE;
return ResultInvalidEnumValue;
}
}