mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #3239 from wwylele/cam-new-frame
cam: convert to ServiceFramework
This commit is contained in:
		
						commit
						c23c39132a
					
				
					 11 changed files with 940 additions and 792 deletions
				
			
		|  | @ -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(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue