cam.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <future>
  7. #include <memory>
  8. #include <vector>
  9. #include "common/bit_set.h"
  10. #include "common/logging/log.h"
  11. #include "core/core_timing.h"
  12. #include "core/frontend/camera/factory.h"
  13. #include "core/hle/ipc.h"
  14. #include "core/hle/ipc_helpers.h"
  15. #include "core/hle/kernel/event.h"
  16. #include "core/hle/result.h"
  17. #include "core/hle/service/cam/cam.h"
  18. #include "core/hle/service/cam/cam_c.h"
  19. #include "core/hle/service/cam/cam_q.h"
  20. #include "core/hle/service/cam/cam_s.h"
  21. #include "core/hle/service/cam/cam_u.h"
  22. #include "core/hle/service/service.h"
  23. #include "core/memory.h"
  24. #include "core/settings.h"
  25. namespace Service {
  26. namespace CAM {
  27. namespace {
  28. struct ContextConfig {
  29. Flip flip;
  30. Effect effect;
  31. OutputFormat format;
  32. Resolution resolution;
  33. };
  34. struct CameraConfig {
  35. std::unique_ptr<Camera::CameraInterface> impl;
  36. std::array<ContextConfig, 2> contexts;
  37. int current_context;
  38. FrameRate frame_rate;
  39. };
  40. struct PortConfig {
  41. int camera_id;
  42. bool is_active; // set when the port is activated by an Activate call.
  43. bool is_pending_receiving; // set if SetReceiving is called when is_busy = false. When
  44. // StartCapture is called then, this will trigger a receiving
  45. // process and reset itself.
  46. bool is_busy; // set when StartCapture is called and reset when StopCapture is called.
  47. bool is_receiving; // set when there is an ongoing receiving process.
  48. bool is_trimming;
  49. u16 x0; // x-coordinate of starting position for trimming
  50. u16 y0; // y-coordinate of starting position for trimming
  51. u16 x1; // x-coordinate of ending position for trimming
  52. u16 y1; // y-coordinate of ending position for trimming
  53. u16 transfer_bytes;
  54. Kernel::SharedPtr<Kernel::Event> completion_event;
  55. Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event;
  56. Kernel::SharedPtr<Kernel::Event> vsync_interrupt_event;
  57. std::future<std::vector<u16>> capture_result; // will hold the received frame.
  58. VAddr dest; // the destination address of a receiving process
  59. u32 dest_size; // the destination size of a receiving process
  60. void Clear() {
  61. completion_event->Clear();
  62. buffer_error_interrupt_event->Clear();
  63. vsync_interrupt_event->Clear();
  64. is_receiving = false;
  65. is_active = false;
  66. is_pending_receiving = false;
  67. is_busy = false;
  68. is_trimming = false;
  69. x0 = 0;
  70. y0 = 0;
  71. x1 = 0;
  72. y1 = 0;
  73. transfer_bytes = 256;
  74. }
  75. };
  76. // built-in resolution parameters
  77. constexpr std::array<Resolution, 8> PRESET_RESOLUTION{{
  78. {640, 480, 0, 0, 639, 479}, // VGA
  79. {320, 240, 0, 0, 639, 479}, // QVGA
  80. {160, 120, 0, 0, 639, 479}, // QQVGA
  81. {352, 288, 26, 0, 613, 479}, // CIF
  82. {176, 144, 26, 0, 613, 479}, // QCIF
  83. {256, 192, 0, 0, 639, 479}, // DS_LCD
  84. {512, 384, 0, 0, 639, 479}, // DS_LCDx4
  85. {400, 240, 0, 48, 639, 431}, // CTR_TOP_LCD
  86. }};
  87. // latency in ms for each frame rate option
  88. constexpr std::array<int, 13> LATENCY_BY_FRAME_RATE{{
  89. 67, // Rate_15
  90. 67, // Rate_15_To_5
  91. 67, // Rate_15_To_2
  92. 100, // Rate_10
  93. 118, // Rate_8_5
  94. 200, // Rate_5
  95. 50, // Rate_20
  96. 50, // Rate_20_To_5
  97. 33, // Rate_30
  98. 33, // Rate_30_To_5
  99. 67, // Rate_15_To_10
  100. 50, // Rate_20_To_10
  101. 33, // Rate_30_To_10
  102. }};
  103. std::array<CameraConfig, NumCameras> cameras;
  104. std::array<PortConfig, 2> ports;
  105. int completion_event_callback;
  106. const ResultCode ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
  107. ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  108. const ResultCode ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM,
  109. ErrorSummary::InvalidArgument, ErrorLevel::Usage);
  110. void CompletionEventCallBack(u64 port_id, int) {
  111. PortConfig& port = ports[port_id];
  112. const CameraConfig& camera = cameras[port.camera_id];
  113. const auto buffer = port.capture_result.get();
  114. if (port.is_trimming) {
  115. u32 trim_width;
  116. u32 trim_height;
  117. const int original_width = camera.contexts[camera.current_context].resolution.width;
  118. const int original_height = camera.contexts[camera.current_context].resolution.height;
  119. if (port.x1 <= port.x0 || port.y1 <= port.y0 || port.x1 > original_width ||
  120. port.y1 > original_height) {
  121. LOG_ERROR(Service_CAM, "Invalid trimming coordinates x0=%u, y0=%u, x1=%u, y1=%u",
  122. port.x0, port.y0, port.x1, port.y1);
  123. trim_width = 0;
  124. trim_height = 0;
  125. } else {
  126. trim_width = port.x1 - port.x0;
  127. trim_height = port.y1 - port.y0;
  128. }
  129. u32 trim_size = (port.x1 - port.x0) * (port.y1 - port.y0) * 2;
  130. if (port.dest_size != trim_size) {
  131. LOG_ERROR(Service_CAM, "The destination size (%u) doesn't match the source (%u)!",
  132. port.dest_size, trim_size);
  133. }
  134. const u32 src_offset = port.y0 * original_width + port.x0;
  135. const u16* src_ptr = buffer.data() + src_offset;
  136. // Note: src_size_left is int because it can be negative if the buffer size doesn't match.
  137. int src_size_left = static_cast<int>((buffer.size() - src_offset) * sizeof(u16));
  138. VAddr dest_ptr = port.dest;
  139. // Note: dest_size_left and line_bytes are int to match the type of src_size_left.
  140. int dest_size_left = static_cast<int>(port.dest_size);
  141. const int line_bytes = static_cast<int>(trim_width * sizeof(u16));
  142. for (u32 y = 0; y < trim_height; ++y) {
  143. int copy_length = std::min({line_bytes, dest_size_left, src_size_left});
  144. if (copy_length <= 0) {
  145. break;
  146. }
  147. Memory::WriteBlock(dest_ptr, src_ptr, copy_length);
  148. dest_ptr += copy_length;
  149. dest_size_left -= copy_length;
  150. src_ptr += original_width;
  151. src_size_left -= original_width * sizeof(u16);
  152. }
  153. } else {
  154. std::size_t buffer_size = buffer.size() * sizeof(u16);
  155. if (port.dest_size != buffer_size) {
  156. LOG_ERROR(Service_CAM, "The destination size (%u) doesn't match the source (%zu)!",
  157. port.dest_size, buffer_size);
  158. }
  159. Memory::WriteBlock(port.dest, buffer.data(), std::min<size_t>(port.dest_size, buffer_size));
  160. }
  161. port.is_receiving = false;
  162. port.completion_event->Signal();
  163. }
  164. // Starts a receiving process on the specified port. This can only be called when is_busy = true and
  165. // is_receiving = false.
  166. void StartReceiving(int port_id) {
  167. PortConfig& port = ports[port_id];
  168. port.is_receiving = true;
  169. // launches a capture task asynchronously
  170. const CameraConfig& camera = cameras[port.camera_id];
  171. port.capture_result =
  172. std::async(std::launch::async, &Camera::CameraInterface::ReceiveFrame, camera.impl.get());
  173. // schedules a completion event according to the frame rate. The event will block on the
  174. // capture task if it is not finished within the expected time
  175. CoreTiming::ScheduleEvent(
  176. msToCycles(LATENCY_BY_FRAME_RATE[static_cast<int>(camera.frame_rate)]),
  177. completion_event_callback, port_id);
  178. }
  179. // Cancels any ongoing receiving processes at the specified port. This is used by functions that
  180. // stop capturing.
  181. // TODO: what is the exact behaviour on real 3DS when stopping capture during an ongoing process?
  182. // Will the completion event still be signaled?
  183. void CancelReceiving(int port_id) {
  184. if (!ports[port_id].is_receiving)
  185. return;
  186. LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process.");
  187. CoreTiming::UnscheduleEvent(completion_event_callback, port_id);
  188. ports[port_id].capture_result.wait();
  189. ports[port_id].is_receiving = false;
  190. }
  191. // Activates the specified port with the specfied camera.
  192. static void ActivatePort(int port_id, int camera_id) {
  193. if (ports[port_id].is_busy && ports[port_id].camera_id != camera_id) {
  194. CancelReceiving(port_id);
  195. cameras[ports[port_id].camera_id].impl->StopCapture();
  196. ports[port_id].is_busy = false;
  197. }
  198. ports[port_id].is_active = true;
  199. ports[port_id].camera_id = camera_id;
  200. }
  201. template <int max_index>
  202. class CommandParamBitSet : public BitSet8 {
  203. public:
  204. explicit CommandParamBitSet(u8 command_param) : BitSet8(command_param) {}
  205. bool IsValid() const {
  206. return m_val < (1 << max_index);
  207. }
  208. bool IsSingle() const {
  209. return IsValid() && Count() == 1;
  210. }
  211. };
  212. using PortSet = CommandParamBitSet<2>;
  213. using ContextSet = CommandParamBitSet<2>;
  214. using CameraSet = CommandParamBitSet<3>;
  215. } // namespace
  216. void StartCapture(Service::Interface* self) {
  217. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0);
  218. const PortSet port_select(rp.Pop<u8>());
  219. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  220. if (port_select.IsValid()) {
  221. for (int i : port_select) {
  222. if (!ports[i].is_busy) {
  223. if (!ports[i].is_active) {
  224. // This doesn't return an error, but seems to put the camera in an undefined
  225. // state
  226. LOG_ERROR(Service_CAM, "port %u hasn't been activated", i);
  227. } else {
  228. cameras[ports[i].camera_id].impl->StartCapture();
  229. ports[i].is_busy = true;
  230. if (ports[i].is_pending_receiving) {
  231. ports[i].is_pending_receiving = false;
  232. StartReceiving(i);
  233. }
  234. }
  235. } else {
  236. LOG_WARNING(Service_CAM, "port %u already started", i);
  237. }
  238. }
  239. rb.Push(RESULT_SUCCESS);
  240. } else {
  241. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  242. rb.Push(ERROR_INVALID_ENUM_VALUE);
  243. }
  244. LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
  245. }
  246. void StopCapture(Service::Interface* self) {
  247. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0);
  248. const PortSet port_select(rp.Pop<u8>());
  249. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  250. if (port_select.IsValid()) {
  251. for (int i : port_select) {
  252. if (ports[i].is_busy) {
  253. CancelReceiving(i);
  254. cameras[ports[i].camera_id].impl->StopCapture();
  255. ports[i].is_busy = false;
  256. } else {
  257. LOG_WARNING(Service_CAM, "port %u already stopped", i);
  258. }
  259. }
  260. rb.Push(RESULT_SUCCESS);
  261. } else {
  262. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  263. rb.Push(ERROR_INVALID_ENUM_VALUE);
  264. }
  265. LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
  266. }
  267. void IsBusy(Service::Interface* self) {
  268. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
  269. const PortSet port_select(rp.Pop<u8>());
  270. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  271. if (port_select.IsValid()) {
  272. bool is_busy = true;
  273. // Note: the behaviour on no or both ports selected are verified against real 3DS.
  274. for (int i : port_select) {
  275. is_busy &= ports[i].is_busy;
  276. }
  277. rb.Push(RESULT_SUCCESS);
  278. rb.Push(is_busy);
  279. } else {
  280. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  281. rb.Push(ERROR_INVALID_ENUM_VALUE);
  282. rb.Skip(1, false);
  283. }
  284. LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
  285. }
  286. void ClearBuffer(Service::Interface* self) {
  287. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0);
  288. const PortSet port_select(rp.Pop<u8>());
  289. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  290. rb.Push(RESULT_SUCCESS);
  291. LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
  292. }
  293. void GetVsyncInterruptEvent(Service::Interface* self) {
  294. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0);
  295. const PortSet port_select(rp.Pop<u8>());
  296. IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
  297. if (port_select.IsSingle()) {
  298. int port = *port_select.begin();
  299. rb.Push(RESULT_SUCCESS);
  300. rb.PushCopyHandles(
  301. Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).Unwrap());
  302. } else {
  303. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  304. rb.Push(ERROR_INVALID_ENUM_VALUE);
  305. rb.PushCopyHandles(0);
  306. }
  307. LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
  308. }
  309. void GetBufferErrorInterruptEvent(Service::Interface* self) {
  310. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0);
  311. const PortSet port_select(rp.Pop<u8>());
  312. IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
  313. if (port_select.IsSingle()) {
  314. int port = *port_select.begin();
  315. rb.Push(RESULT_SUCCESS);
  316. rb.PushCopyHandles(
  317. Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).Unwrap());
  318. } else {
  319. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  320. rb.Push(ERROR_INVALID_ENUM_VALUE);
  321. rb.PushCopyHandles(0);
  322. }
  323. LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
  324. }
  325. void SetReceiving(Service::Interface* self) {
  326. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2);
  327. const VAddr dest = rp.Pop<u32>();
  328. const PortSet port_select(rp.Pop<u8>());
  329. const u32 image_size = rp.Pop<u32>();
  330. const u16 trans_unit = rp.Pop<u16>();
  331. rp.PopHandle(); // Handle to destination process. not used
  332. IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
  333. if (port_select.IsSingle()) {
  334. int port_id = *port_select.begin();
  335. PortConfig& port = ports[port_id];
  336. CancelReceiving(port_id);
  337. port.completion_event->Clear();
  338. port.dest = dest;
  339. port.dest_size = image_size;
  340. if (port.is_busy) {
  341. StartReceiving(port_id);
  342. } else {
  343. port.is_pending_receiving = true;
  344. }
  345. rb.Push(RESULT_SUCCESS);
  346. rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).Unwrap());
  347. } else {
  348. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  349. rb.Push(ERROR_INVALID_ENUM_VALUE);
  350. rb.PushCopyHandles(0);
  351. }
  352. LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest,
  353. port_select.m_val, image_size, trans_unit);
  354. }
  355. void IsFinishedReceiving(Service::Interface* self) {
  356. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0);
  357. const PortSet port_select(rp.Pop<u8>());
  358. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  359. if (port_select.IsSingle()) {
  360. int port = *port_select.begin();
  361. bool is_busy = ports[port].is_receiving || ports[port].is_pending_receiving;
  362. rb.Push(RESULT_SUCCESS);
  363. rb.Push(!is_busy);
  364. } else {
  365. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  366. rb.Push(ERROR_INVALID_ENUM_VALUE);
  367. rb.Skip(1, false);
  368. }
  369. LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
  370. }
  371. void SetTransferLines(Service::Interface* self) {
  372. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0);
  373. const PortSet port_select(rp.Pop<u8>());
  374. const u16 transfer_lines = rp.Pop<u16>();
  375. const u16 width = rp.Pop<u16>();
  376. const u16 height = rp.Pop<u16>();
  377. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  378. if (port_select.IsValid()) {
  379. for (int i : port_select) {
  380. ports[i].transfer_bytes = transfer_lines * width * 2;
  381. }
  382. rb.Push(RESULT_SUCCESS);
  383. } else {
  384. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  385. rb.Push(ERROR_INVALID_ENUM_VALUE);
  386. }
  387. LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u",
  388. port_select.m_val, transfer_lines, width, height);
  389. }
  390. void GetMaxLines(Service::Interface* self) {
  391. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0);
  392. const u16 width = rp.Pop<u16>();
  393. const u16 height = rp.Pop<u16>();
  394. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  395. // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
  396. constexpr u32 MIN_TRANSFER_UNIT = 256;
  397. constexpr u32 MAX_BUFFER_SIZE = 2560;
  398. if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
  399. rb.Push(ERROR_OUT_OF_RANGE);
  400. rb.Skip(1, false);
  401. } else {
  402. u32 lines = MAX_BUFFER_SIZE / width;
  403. if (lines > height) {
  404. lines = height;
  405. }
  406. ResultCode result = RESULT_SUCCESS;
  407. while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) {
  408. --lines;
  409. if (lines == 0) {
  410. result = ERROR_OUT_OF_RANGE;
  411. break;
  412. }
  413. }
  414. rb.Push(result);
  415. rb.Push(lines);
  416. }
  417. LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
  418. }
  419. void SetTransferBytes(Service::Interface* self) {
  420. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0);
  421. const PortSet port_select(rp.Pop<u8>());
  422. const u16 transfer_bytes = rp.Pop<u16>();
  423. const u16 width = rp.Pop<u16>();
  424. const u16 height = rp.Pop<u16>();
  425. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  426. if (port_select.IsValid()) {
  427. for (int i : port_select) {
  428. ports[i].transfer_bytes = transfer_bytes;
  429. }
  430. rb.Push(RESULT_SUCCESS);
  431. } else {
  432. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  433. rb.Push(ERROR_INVALID_ENUM_VALUE);
  434. }
  435. LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u",
  436. port_select.m_val, transfer_bytes, width, height);
  437. }
  438. void GetTransferBytes(Service::Interface* self) {
  439. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0);
  440. const PortSet port_select(rp.Pop<u8>());
  441. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  442. if (port_select.IsSingle()) {
  443. int port = *port_select.begin();
  444. rb.Push(RESULT_SUCCESS);
  445. rb.Push(ports[port].transfer_bytes);
  446. } else {
  447. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  448. rb.Push(ERROR_INVALID_ENUM_VALUE);
  449. rb.Skip(1, false);
  450. }
  451. LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val);
  452. }
  453. void GetMaxBytes(Service::Interface* self) {
  454. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0);
  455. const u16 width = rp.Pop<u16>();
  456. const u16 height = rp.Pop<u16>();
  457. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  458. // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
  459. constexpr u32 MIN_TRANSFER_UNIT = 256;
  460. constexpr u32 MAX_BUFFER_SIZE = 2560;
  461. if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
  462. rb.Push(ERROR_OUT_OF_RANGE);
  463. rb.Skip(1, false);
  464. } else {
  465. u32 bytes = MAX_BUFFER_SIZE;
  466. while (width * height * 2 % bytes != 0) {
  467. bytes -= MIN_TRANSFER_UNIT;
  468. }
  469. rb.Push(RESULT_SUCCESS);
  470. rb.Push(bytes);
  471. }
  472. LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
  473. }
  474. void SetTrimming(Service::Interface* self) {
  475. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0);
  476. const PortSet port_select(rp.Pop<u8>());
  477. const bool trim = rp.Pop<bool>();
  478. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  479. if (port_select.IsValid()) {
  480. for (int i : port_select) {
  481. ports[i].is_trimming = trim;
  482. }
  483. rb.Push(RESULT_SUCCESS);
  484. } else {
  485. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  486. rb.Push(ERROR_INVALID_ENUM_VALUE);
  487. }
  488. LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim);
  489. }
  490. void IsTrimming(Service::Interface* self) {
  491. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0);
  492. const PortSet port_select(rp.Pop<u8>());
  493. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  494. if (port_select.IsSingle()) {
  495. int port = *port_select.begin();
  496. rb.Push(RESULT_SUCCESS);
  497. rb.Push(ports[port].is_trimming);
  498. } else {
  499. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  500. rb.Push(ERROR_INVALID_ENUM_VALUE);
  501. rb.Skip(1, false);
  502. }
  503. LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
  504. }
  505. void SetTrimmingParams(Service::Interface* self) {
  506. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0);
  507. const PortSet port_select(rp.Pop<u8>());
  508. const u16 x0 = rp.Pop<u16>();
  509. const u16 y0 = rp.Pop<u16>();
  510. const u16 x1 = rp.Pop<u16>();
  511. const u16 y1 = rp.Pop<u16>();
  512. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  513. if (port_select.IsValid()) {
  514. for (int i : port_select) {
  515. ports[i].x0 = x0;
  516. ports[i].y0 = y0;
  517. ports[i].x1 = x1;
  518. ports[i].y1 = y1;
  519. }
  520. rb.Push(RESULT_SUCCESS);
  521. } else {
  522. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  523. rb.Push(ERROR_INVALID_ENUM_VALUE);
  524. }
  525. LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val,
  526. x0, y0, x1, y1);
  527. }
  528. void GetTrimmingParams(Service::Interface* self) {
  529. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0);
  530. const PortSet port_select(rp.Pop<u8>());
  531. IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
  532. if (port_select.IsSingle()) {
  533. int port = *port_select.begin();
  534. rb.Push(RESULT_SUCCESS);
  535. rb.Push(ports[port].x0);
  536. rb.Push(ports[port].y0);
  537. rb.Push(ports[port].x1);
  538. rb.Push(ports[port].y1);
  539. } else {
  540. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  541. rb.Push(ERROR_INVALID_ENUM_VALUE);
  542. rb.Skip(4, false);
  543. }
  544. LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
  545. }
  546. void SetTrimmingParamsCenter(Service::Interface* self) {
  547. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0);
  548. const PortSet port_select(rp.Pop<u8>());
  549. const u16 trim_w = rp.Pop<u16>();
  550. const u16 trim_h = rp.Pop<u16>();
  551. const u16 cam_w = rp.Pop<u16>();
  552. const u16 cam_h = rp.Pop<u16>();
  553. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  554. if (port_select.IsValid()) {
  555. for (int i : port_select) {
  556. ports[i].x0 = (cam_w - trim_w) / 2;
  557. ports[i].y0 = (cam_h - trim_h) / 2;
  558. ports[i].x1 = ports[i].x0 + trim_w;
  559. ports[i].y1 = ports[i].y0 + trim_h;
  560. }
  561. rb.Push(RESULT_SUCCESS);
  562. } else {
  563. LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
  564. rb.Push(ERROR_INVALID_ENUM_VALUE);
  565. }
  566. LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u",
  567. port_select.m_val, trim_w, trim_h, cam_w, cam_h);
  568. }
  569. void Activate(Service::Interface* self) {
  570. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0);
  571. const CameraSet camera_select(rp.Pop<u8>());
  572. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  573. if (camera_select.IsValid()) {
  574. if (camera_select.m_val == 0) { // deactive all
  575. for (int i = 0; i < 2; ++i) {
  576. if (ports[i].is_busy) {
  577. CancelReceiving(i);
  578. cameras[ports[i].camera_id].impl->StopCapture();
  579. ports[i].is_busy = false;
  580. }
  581. ports[i].is_active = false;
  582. }
  583. rb.Push(RESULT_SUCCESS);
  584. } else if (camera_select[0] && camera_select[1]) {
  585. LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated");
  586. rb.Push(ERROR_INVALID_ENUM_VALUE);
  587. } else {
  588. if (camera_select[0]) {
  589. ActivatePort(0, 0);
  590. } else if (camera_select[1]) {
  591. ActivatePort(0, 1);
  592. }
  593. if (camera_select[2]) {
  594. ActivatePort(1, 2);
  595. }
  596. rb.Push(RESULT_SUCCESS);
  597. }
  598. } else {
  599. LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
  600. rb.Push(ERROR_INVALID_ENUM_VALUE);
  601. }
  602. LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val);
  603. }
  604. void SwitchContext(Service::Interface* self) {
  605. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0);
  606. const CameraSet camera_select(rp.Pop<u8>());
  607. const ContextSet context_select(rp.Pop<u8>());
  608. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  609. if (camera_select.IsValid() && context_select.IsSingle()) {
  610. int context = *context_select.begin();
  611. for (int camera : camera_select) {
  612. cameras[camera].current_context = context;
  613. const ContextConfig& context_config = cameras[camera].contexts[context];
  614. cameras[camera].impl->SetFlip(context_config.flip);
  615. cameras[camera].impl->SetEffect(context_config.effect);
  616. cameras[camera].impl->SetFormat(context_config.format);
  617. cameras[camera].impl->SetResolution(context_config.resolution);
  618. }
  619. rb.Push(RESULT_SUCCESS);
  620. } else {
  621. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
  622. context_select.m_val);
  623. rb.Push(ERROR_INVALID_ENUM_VALUE);
  624. }
  625. LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val,
  626. context_select.m_val);
  627. }
  628. void FlipImage(Service::Interface* self) {
  629. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0);
  630. const CameraSet camera_select(rp.Pop<u8>());
  631. const Flip flip = static_cast<Flip>(rp.Pop<u8>());
  632. const ContextSet context_select(rp.Pop<u8>());
  633. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  634. if (camera_select.IsValid() && context_select.IsValid()) {
  635. for (int camera : camera_select) {
  636. for (int context : context_select) {
  637. cameras[camera].contexts[context].flip = flip;
  638. if (cameras[camera].current_context == context) {
  639. cameras[camera].impl->SetFlip(flip);
  640. }
  641. }
  642. }
  643. rb.Push(RESULT_SUCCESS);
  644. } else {
  645. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
  646. context_select.m_val);
  647. rb.Push(ERROR_INVALID_ENUM_VALUE);
  648. }
  649. LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u",
  650. camera_select.m_val, static_cast<int>(flip), context_select.m_val);
  651. }
  652. void SetDetailSize(Service::Interface* self) {
  653. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0);
  654. const CameraSet camera_select(rp.Pop<u8>());
  655. Resolution resolution;
  656. resolution.width = rp.Pop<u16>();
  657. resolution.height = rp.Pop<u16>();
  658. resolution.crop_x0 = rp.Pop<u16>();
  659. resolution.crop_y0 = rp.Pop<u16>();
  660. resolution.crop_x1 = rp.Pop<u16>();
  661. resolution.crop_y1 = rp.Pop<u16>();
  662. const ContextSet context_select(rp.Pop<u8>());
  663. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  664. if (camera_select.IsValid() && context_select.IsValid()) {
  665. for (int camera : camera_select) {
  666. for (int context : context_select) {
  667. cameras[camera].contexts[context].resolution = resolution;
  668. if (cameras[camera].current_context == context) {
  669. cameras[camera].impl->SetResolution(resolution);
  670. }
  671. }
  672. }
  673. rb.Push(RESULT_SUCCESS);
  674. } else {
  675. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
  676. context_select.m_val);
  677. rb.Push(ERROR_INVALID_ENUM_VALUE);
  678. }
  679. LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, "
  680. "crop_x1=%u, crop_y1=%u, context_select=%u",
  681. camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0,
  682. resolution.crop_y0, resolution.crop_x1, resolution.crop_y1, context_select.m_val);
  683. }
  684. void SetSize(Service::Interface* self) {
  685. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0);
  686. const CameraSet camera_select(rp.Pop<u8>());
  687. const u8 size = rp.Pop<u8>();
  688. const ContextSet context_select(rp.Pop<u8>());
  689. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  690. if (camera_select.IsValid() && context_select.IsValid()) {
  691. for (int camera : camera_select) {
  692. for (int context : context_select) {
  693. cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size];
  694. if (cameras[camera].current_context == context) {
  695. cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]);
  696. }
  697. }
  698. }
  699. rb.Push(RESULT_SUCCESS);
  700. } else {
  701. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
  702. context_select.m_val);
  703. rb.Push(ERROR_INVALID_ENUM_VALUE);
  704. }
  705. LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u",
  706. camera_select.m_val, size, context_select.m_val);
  707. }
  708. void SetFrameRate(Service::Interface* self) {
  709. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0);
  710. const CameraSet camera_select(rp.Pop<u8>());
  711. const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
  712. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  713. if (camera_select.IsValid()) {
  714. for (int camera : camera_select) {
  715. cameras[camera].frame_rate = frame_rate;
  716. // TODO(wwylele): consider hinting the actual camera with the expected frame rate
  717. }
  718. rb.Push(RESULT_SUCCESS);
  719. } else {
  720. LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
  721. rb.Push(ERROR_INVALID_ENUM_VALUE);
  722. }
  723. LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d",
  724. camera_select.m_val, static_cast<int>(frame_rate));
  725. }
  726. void SetEffect(Service::Interface* self) {
  727. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0);
  728. const CameraSet camera_select(rp.Pop<u8>());
  729. const Effect effect = static_cast<Effect>(rp.Pop<u8>());
  730. const ContextSet context_select(rp.Pop<u8>());
  731. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  732. if (camera_select.IsValid() && context_select.IsValid()) {
  733. for (int camera : camera_select) {
  734. for (int context : context_select) {
  735. cameras[camera].contexts[context].effect = effect;
  736. if (cameras[camera].current_context == context) {
  737. cameras[camera].impl->SetEffect(effect);
  738. }
  739. }
  740. }
  741. rb.Push(RESULT_SUCCESS);
  742. } else {
  743. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
  744. context_select.m_val);
  745. rb.Push(ERROR_INVALID_ENUM_VALUE);
  746. }
  747. LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u",
  748. camera_select.m_val, static_cast<int>(effect), context_select.m_val);
  749. }
  750. void SetOutputFormat(Service::Interface* self) {
  751. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0);
  752. const CameraSet camera_select(rp.Pop<u8>());
  753. const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
  754. const ContextSet context_select(rp.Pop<u8>());
  755. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  756. if (camera_select.IsValid() && context_select.IsValid()) {
  757. for (int camera : camera_select) {
  758. for (int context : context_select) {
  759. cameras[camera].contexts[context].format = format;
  760. if (cameras[camera].current_context == context) {
  761. cameras[camera].impl->SetFormat(format);
  762. }
  763. }
  764. }
  765. rb.Push(RESULT_SUCCESS);
  766. } else {
  767. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
  768. context_select.m_val);
  769. rb.Push(ERROR_INVALID_ENUM_VALUE);
  770. }
  771. LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u",
  772. camera_select.m_val, static_cast<int>(format), context_select.m_val);
  773. }
  774. void SynchronizeVsyncTiming(Service::Interface* self) {
  775. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0);
  776. const u8 camera_select1 = rp.Pop<u8>();
  777. const u8 camera_select2 = rp.Pop<u8>();
  778. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  779. rb.Push(RESULT_SUCCESS);
  780. LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u",
  781. camera_select1, camera_select2);
  782. }
  783. void GetStereoCameraCalibrationData(Service::Interface* self) {
  784. IPC::RequestBuilder rb =
  785. IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0);
  786. // Default values taken from yuriks' 3DS. Valid data is required here or games using the
  787. // calibration get stuck in an infinite CPU loop.
  788. StereoCameraCalibrationData data = {};
  789. data.isValidRotationXY = 0;
  790. data.scale = 1.001776f;
  791. data.rotationZ = 0.008322907f;
  792. data.translationX = -87.70484f;
  793. data.translationY = -7.640977f;
  794. data.rotationX = 0.0f;
  795. data.rotationY = 0.0f;
  796. data.angleOfViewRight = 64.66875f;
  797. data.angleOfViewLeft = 64.76067f;
  798. data.distanceToChart = 250.0f;
  799. data.distanceCameras = 35.0f;
  800. data.imageWidth = 640;
  801. data.imageHeight = 480;
  802. rb.Push(RESULT_SUCCESS);
  803. rb.PushRaw(data);
  804. LOG_TRACE(Service_CAM, "called");
  805. }
  806. void SetPackageParameterWithoutContext(Service::Interface* self) {
  807. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0);
  808. PackageParameterWithoutContext package;
  809. rp.PopRaw(package);
  810. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  811. rb.Push(RESULT_SUCCESS);
  812. LOG_WARNING(Service_CAM, "(STUBBED) called");
  813. }
  814. template <typename PackageParameterType>
  815. static ResultCode SetPackageParameter(const PackageParameterType& package) {
  816. const CameraSet camera_select(package.camera_select);
  817. const ContextSet context_select(package.context_select);
  818. if (camera_select.IsValid() && context_select.IsValid()) {
  819. for (int camera_id : camera_select) {
  820. CameraConfig& camera = cameras[camera_id];
  821. for (int context_id : context_select) {
  822. ContextConfig& context = camera.contexts[context_id];
  823. context.effect = package.effect;
  824. context.flip = package.flip;
  825. context.resolution = package.GetResolution();
  826. if (context_id == camera.current_context) {
  827. camera.impl->SetEffect(context.effect);
  828. camera.impl->SetFlip(context.flip);
  829. camera.impl->SetResolution(context.resolution);
  830. }
  831. }
  832. }
  833. return RESULT_SUCCESS;
  834. } else {
  835. LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select,
  836. package.context_select);
  837. return ERROR_INVALID_ENUM_VALUE;
  838. }
  839. }
  840. Resolution PackageParameterWithContext::GetResolution() const {
  841. return PRESET_RESOLUTION[static_cast<int>(size)];
  842. }
  843. void SetPackageParameterWithContext(Service::Interface* self) {
  844. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0);
  845. PackageParameterWithContext package;
  846. rp.PopRaw(package);
  847. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  848. ResultCode result = SetPackageParameter(package);
  849. rb.Push(result);
  850. LOG_DEBUG(Service_CAM, "called");
  851. }
  852. void SetPackageParameterWithContextDetail(Service::Interface* self) {
  853. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0);
  854. PackageParameterWithContextDetail package;
  855. rp.PopRaw(package);
  856. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  857. ResultCode result = SetPackageParameter(package);
  858. rb.Push(result);
  859. LOG_DEBUG(Service_CAM, "called");
  860. }
  861. void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
  862. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0);
  863. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  864. rb.Push(RESULT_SUCCESS);
  865. rb.Push<u32>(0);
  866. LOG_WARNING(Service_CAM, "(STUBBED) called");
  867. }
  868. void PlayShutterSound(Service::Interface* self) {
  869. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0);
  870. u8 sound_id = rp.Pop<u8>();
  871. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  872. rb.Push(RESULT_SUCCESS);
  873. LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id);
  874. }
  875. void DriverInitialize(Service::Interface* self) {
  876. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0);
  877. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  878. for (int camera_id = 0; camera_id < NumCameras; ++camera_id) {
  879. CameraConfig& camera = cameras[camera_id];
  880. camera.current_context = 0;
  881. for (int context_id = 0; context_id < 2; ++context_id) {
  882. // Note: the following default values are verified against real 3DS
  883. ContextConfig& context = camera.contexts[context_id];
  884. context.flip = camera_id == 1 ? Flip::Horizontal : Flip::None;
  885. context.effect = Effect::None;
  886. context.format = OutputFormat::YUV422;
  887. context.resolution =
  888. context_id == 0 ? PRESET_RESOLUTION[5 /*DS_LCD*/] : PRESET_RESOLUTION[0 /*VGA*/];
  889. }
  890. camera.impl = Camera::CreateCamera(Settings::values.camera_name[camera_id],
  891. Settings::values.camera_config[camera_id]);
  892. camera.impl->SetFlip(camera.contexts[0].flip);
  893. camera.impl->SetEffect(camera.contexts[0].effect);
  894. camera.impl->SetFormat(camera.contexts[0].format);
  895. camera.impl->SetResolution(camera.contexts[0].resolution);
  896. }
  897. for (PortConfig& port : ports) {
  898. port.Clear();
  899. }
  900. rb.Push(RESULT_SUCCESS);
  901. LOG_DEBUG(Service_CAM, "called");
  902. }
  903. void DriverFinalize(Service::Interface* self) {
  904. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0);
  905. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  906. CancelReceiving(0);
  907. CancelReceiving(1);
  908. for (CameraConfig& camera : cameras) {
  909. camera.impl = nullptr;
  910. }
  911. rb.Push(RESULT_SUCCESS);
  912. LOG_DEBUG(Service_CAM, "called");
  913. }
  914. void Init() {
  915. using namespace Kernel;
  916. AddService(new CAM_C_Interface);
  917. AddService(new CAM_Q_Interface);
  918. AddService(new CAM_S_Interface);
  919. AddService(new CAM_U_Interface);
  920. for (PortConfig& port : ports) {
  921. port.completion_event = Event::Create(ResetType::Sticky, "CAM_U::completion_event");
  922. port.buffer_error_interrupt_event =
  923. Event::Create(ResetType::OneShot, "CAM_U::buffer_error_interrupt_event");
  924. port.vsync_interrupt_event =
  925. Event::Create(ResetType::OneShot, "CAM_U::vsync_interrupt_event");
  926. }
  927. completion_event_callback =
  928. CoreTiming::RegisterEvent("CAM_U::CompletionEventCallBack", CompletionEventCallBack);
  929. }
  930. void Shutdown() {
  931. CancelReceiving(0);
  932. CancelReceiving(1);
  933. for (PortConfig& port : ports) {
  934. port.completion_event = nullptr;
  935. port.buffer_error_interrupt_event = nullptr;
  936. port.vsync_interrupt_event = nullptr;
  937. }
  938. for (CameraConfig& camera : cameras) {
  939. camera.impl = nullptr;
  940. }
  941. }
  942. } // namespace CAM
  943. } // namespace Service