summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/cam/cam.cpp545
-rw-r--r--src/core/hle/service/cam/cam.h13
2 files changed, 265 insertions, 293 deletions
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 95665e754..85af70a3f 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -55,7 +55,7 @@ struct PortConfig {
55 u16 x1; // x-coordinate of ending position for trimming 55 u16 x1; // x-coordinate of ending position for trimming
56 u16 y1; // y-coordinate of ending position for trimming 56 u16 y1; // y-coordinate of ending position for trimming
57 57
58 u32 transfer_bytes; 58 u16 transfer_bytes;
59 59
60 Kernel::SharedPtr<Kernel::Event> completion_event; 60 Kernel::SharedPtr<Kernel::Event> completion_event;
61 Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event; 61 Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event;
@@ -225,8 +225,7 @@ static void ActivatePort(int port_id, int camera_id) {
225template <int max_index> 225template <int max_index>
226class CommandParamBitSet : public BitSet8 { 226class CommandParamBitSet : public BitSet8 {
227public: 227public:
228 explicit CommandParamBitSet(u32 command_param) 228 explicit CommandParamBitSet(u8 command_param) : BitSet8(command_param) {}
229 : BitSet8(static_cast<u8>(command_param & 0xFF)) {}
230 229
231 bool IsValid() const { 230 bool IsValid() const {
232 return m_val < (1 << max_index); 231 return m_val < (1 << max_index);
@@ -244,9 +243,10 @@ using CameraSet = CommandParamBitSet<3>;
244} // namespace 243} // namespace
245 244
246void StartCapture(Service::Interface* self) { 245void StartCapture(Service::Interface* self) {
247 u32* cmd_buff = Kernel::GetCommandBuffer(); 246 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0);
247 const PortSet port_select(rp.Pop<u8>());
248 248
249 const PortSet port_select(cmd_buff[1]); 249 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
250 250
251 if (port_select.IsValid()) { 251 if (port_select.IsValid()) {
252 for (int i : port_select) { 252 for (int i : port_select) {
@@ -267,21 +267,20 @@ void StartCapture(Service::Interface* self) {
267 LOG_WARNING(Service_CAM, "port %u already started", i); 267 LOG_WARNING(Service_CAM, "port %u already started", i);
268 } 268 }
269 } 269 }
270 cmd_buff[1] = RESULT_SUCCESS.raw; 270 rb.Push(RESULT_SUCCESS);
271 } else { 271 } else {
272 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 272 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
273 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 273 rb.Push(ERROR_INVALID_ENUM_VALUE);
274 } 274 }
275 275
276 cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
277
278 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 276 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
279} 277}
280 278
281void StopCapture(Service::Interface* self) { 279void StopCapture(Service::Interface* self) {
282 u32* cmd_buff = Kernel::GetCommandBuffer(); 280 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0);
281 const PortSet port_select(rp.Pop<u8>());
283 282
284 const PortSet port_select(cmd_buff[1]); 283 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
285 284
286 if (port_select.IsValid()) { 285 if (port_select.IsValid()) {
287 for (int i : port_select) { 286 for (int i : port_select) {
@@ -293,21 +292,20 @@ void StopCapture(Service::Interface* self) {
293 LOG_WARNING(Service_CAM, "port %u already stopped", i); 292 LOG_WARNING(Service_CAM, "port %u already stopped", i);
294 } 293 }
295 } 294 }
296 cmd_buff[1] = RESULT_SUCCESS.raw; 295 rb.Push(RESULT_SUCCESS);
297 } else { 296 } else {
298 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 297 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
299 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 298 rb.Push(ERROR_INVALID_ENUM_VALUE);
300 } 299 }
301 300
302 cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0);
303
304 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 301 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
305} 302}
306 303
307void IsBusy(Service::Interface* self) { 304void IsBusy(Service::Interface* self) {
308 u32* cmd_buff = Kernel::GetCommandBuffer(); 305 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
306 const PortSet port_select(rp.Pop<u8>());
309 307
310 const PortSet port_select(cmd_buff[1]); 308 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
311 309
312 if (port_select.IsValid()) { 310 if (port_select.IsValid()) {
313 bool is_busy = true; 311 bool is_busy = true;
@@ -315,80 +313,74 @@ void IsBusy(Service::Interface* self) {
315 for (int i : port_select) { 313 for (int i : port_select) {
316 is_busy &= ports[i].is_busy; 314 is_busy &= ports[i].is_busy;
317 } 315 }
318 cmd_buff[1] = RESULT_SUCCESS.raw; 316 rb.Push(RESULT_SUCCESS);
319 cmd_buff[2] = is_busy ? 1 : 0; 317 rb.Push(is_busy);
320 } else { 318 } else {
321 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 319 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
322 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 320 rb.Push(ERROR_INVALID_ENUM_VALUE);
321 rb.Skip(1, false);
323 } 322 }
324 323
325 cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0);
326
327 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 324 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
328} 325}
329 326
330void ClearBuffer(Service::Interface* self) { 327void ClearBuffer(Service::Interface* self) {
331 u32* cmd_buff = Kernel::GetCommandBuffer(); 328 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0);
332 329 const PortSet port_select(rp.Pop<u8>());
333 const PortSet port_select(cmd_buff[1]);
334 330
335 cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0); 331 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
336 cmd_buff[1] = RESULT_SUCCESS.raw; 332 rb.Push(RESULT_SUCCESS);
337 333
338 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); 334 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
339} 335}
340 336
341void GetVsyncInterruptEvent(Service::Interface* self) { 337void GetVsyncInterruptEvent(Service::Interface* self) {
342 u32* cmd_buff = Kernel::GetCommandBuffer(); 338 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0);
343 339 const PortSet port_select(rp.Pop<u8>());
344 const PortSet port_select(cmd_buff[1]);
345 340
341 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
346 if (port_select.IsSingle()) { 342 if (port_select.IsSingle()) {
347 int port = *port_select.begin(); 343 int port = *port_select.begin();
348 cmd_buff[1] = RESULT_SUCCESS.raw; 344 rb.Push(RESULT_SUCCESS);
349 cmd_buff[2] = IPC::CopyHandleDesc(); 345 rb.PushCopyHandles(
350 cmd_buff[3] = Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom(); 346 Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom());
351 } else { 347 } else {
352 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 348 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
353 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 349 rb.Push(ERROR_INVALID_ENUM_VALUE);
354 cmd_buff[2] = IPC::CopyHandleDesc(); 350 rb.PushCopyHandles(0);
355 cmd_buff[2] = 0;
356 } 351 }
357 352
358 cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2);
359
360 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); 353 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
361} 354}
362 355
363void GetBufferErrorInterruptEvent(Service::Interface* self) { 356void GetBufferErrorInterruptEvent(Service::Interface* self) {
364 u32* cmd_buff = Kernel::GetCommandBuffer(); 357 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0);
365 358 const PortSet port_select(rp.Pop<u8>());
366 const PortSet port_select(cmd_buff[1]);
367 359
360 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
368 if (port_select.IsSingle()) { 361 if (port_select.IsSingle()) {
369 int port = *port_select.begin(); 362 int port = *port_select.begin();
370 cmd_buff[1] = RESULT_SUCCESS.raw; 363 rb.Push(RESULT_SUCCESS);
371 cmd_buff[2] = IPC::CopyHandleDesc(); 364 rb.PushCopyHandles(
372 cmd_buff[3] = 365 Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom());
373 Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom();
374 } else { 366 } else {
375 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 367 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
376 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 368 rb.Push(ERROR_INVALID_ENUM_VALUE);
377 cmd_buff[2] = IPC::CopyHandleDesc(); 369 rb.PushCopyHandles(0);
378 cmd_buff[2] = 0;
379 } 370 }
380 371
381 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); 372 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
382} 373}
383 374
384void SetReceiving(Service::Interface* self) { 375void SetReceiving(Service::Interface* self) {
385 u32* cmd_buff = Kernel::GetCommandBuffer(); 376 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2);
386 377 const VAddr dest = rp.Pop<u32>();
387 const VAddr dest = cmd_buff[1]; 378 const PortSet port_select(rp.Pop<u8>());
388 const PortSet port_select(cmd_buff[2]); 379 const u32 image_size = rp.Pop<u32>();
389 const u32 image_size = cmd_buff[3]; 380 const u16 trans_unit = rp.Pop<u16>();
390 const u32 trans_unit = cmd_buff[4] & 0xFFFF; 381 rp.PopHandle(); // Handle to destination process. not used
391 382
383 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
392 if (port_select.IsSingle()) { 384 if (port_select.IsSingle()) {
393 int port_id = *port_select.begin(); 385 int port_id = *port_select.begin();
394 PortConfig& port = ports[port_id]; 386 PortConfig& port = ports[port_id];
@@ -403,149 +395,145 @@ void SetReceiving(Service::Interface* self) {
403 port.is_pending_receiving = true; 395 port.is_pending_receiving = true;
404 } 396 }
405 397
406 cmd_buff[1] = RESULT_SUCCESS.raw; 398 rb.Push(RESULT_SUCCESS);
407 cmd_buff[2] = IPC::CopyHandleDesc(); 399 rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).MoveFrom());
408 cmd_buff[3] = Kernel::g_handle_table.Create(port.completion_event).MoveFrom();
409 } else { 400 } else {
410 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 401 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
411 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 402 rb.Push(ERROR_INVALID_ENUM_VALUE);
403 rb.PushCopyHandles(0);
412 } 404 }
413 405
414 cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2);
415
416 LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest, 406 LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest,
417 port_select.m_val, image_size, trans_unit); 407 port_select.m_val, image_size, trans_unit);
418} 408}
419 409
420void IsFinishedReceiving(Service::Interface* self) { 410void IsFinishedReceiving(Service::Interface* self) {
421 u32* cmd_buff = Kernel::GetCommandBuffer(); 411 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0);
422 412 const PortSet port_select(rp.Pop<u8>());
423 const PortSet port_select(cmd_buff[1]);
424 413
414 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
425 if (port_select.IsSingle()) { 415 if (port_select.IsSingle()) {
426 int port = *port_select.begin(); 416 int port = *port_select.begin();
427 cmd_buff[1] = RESULT_SUCCESS.raw; 417 bool is_busy = ports[port].is_receiving || ports[port].is_pending_receiving;
428 cmd_buff[2] = (ports[port].is_receiving || ports[port].is_pending_receiving) ? 0 : 1; 418 rb.Push(RESULT_SUCCESS);
419 rb.Push(!is_busy);
429 } else { 420 } else {
430 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 421 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
431 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 422 rb.Push(ERROR_INVALID_ENUM_VALUE);
423 rb.Skip(1, false);
432 } 424 }
433 425
434 cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
435
436 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 426 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
437} 427}
438 428
439void SetTransferLines(Service::Interface* self) { 429void SetTransferLines(Service::Interface* self) {
440 u32* cmd_buff = Kernel::GetCommandBuffer(); 430 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0);
441 431 const PortSet port_select(rp.Pop<u8>());
442 const PortSet port_select(cmd_buff[1]); 432 const u16 transfer_lines = rp.Pop<u16>();
443 const u32 transfer_lines = cmd_buff[2] & 0xFFFF; 433 const u16 width = rp.Pop<u16>();
444 const u32 width = cmd_buff[3] & 0xFFFF; 434 const u16 height = rp.Pop<u16>();
445 const u32 height = cmd_buff[4] & 0xFFFF;
446 435
436 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
447 if (port_select.IsValid()) { 437 if (port_select.IsValid()) {
448 for (int i : port_select) { 438 for (int i : port_select) {
449 ports[i].transfer_bytes = transfer_lines * width * 2; 439 ports[i].transfer_bytes = transfer_lines * width * 2;
450 } 440 }
451 cmd_buff[1] = RESULT_SUCCESS.raw; 441 rb.Push(RESULT_SUCCESS);
452 } else { 442 } else {
453 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 443 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
454 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 444 rb.Push(ERROR_INVALID_ENUM_VALUE);
455 } 445 }
456 446
457 cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
458
459 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u", 447 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u",
460 port_select.m_val, transfer_lines, width, height); 448 port_select.m_val, transfer_lines, width, height);
461} 449}
462 450
463void GetMaxLines(Service::Interface* self) { 451void GetMaxLines(Service::Interface* self) {
464 u32* cmd_buff = Kernel::GetCommandBuffer(); 452 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0);
453 const u16 width = rp.Pop<u16>();
454 const u16 height = rp.Pop<u16>();
465 455
466 const u32 width = cmd_buff[1] & 0xFFFF; 456 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
467 const u32 height = cmd_buff[2] & 0xFFFF;
468 457
469 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 458 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
470 constexpr u32 MIN_TRANSFER_UNIT = 256; 459 constexpr u32 MIN_TRANSFER_UNIT = 256;
471 constexpr u32 MAX_BUFFER_SIZE = 2560; 460 constexpr u32 MAX_BUFFER_SIZE = 2560;
472 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { 461 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
473 cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; 462 rb.Push(ERROR_OUT_OF_RANGE);
463 rb.Skip(1, false);
474 } else { 464 } else {
475 u32 lines = MAX_BUFFER_SIZE / width; 465 u32 lines = MAX_BUFFER_SIZE / width;
476 if (lines > height) { 466 if (lines > height) {
477 lines = height; 467 lines = height;
478 } 468 }
479 cmd_buff[1] = RESULT_SUCCESS.raw; 469 ResultCode result = RESULT_SUCCESS;
480 while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) { 470 while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) {
481 --lines; 471 --lines;
482 if (lines == 0) { 472 if (lines == 0) {
483 cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; 473 result = ERROR_OUT_OF_RANGE;
484 break; 474 break;
485 } 475 }
486 } 476 }
487 cmd_buff[2] = lines; 477 rb.Push(result);
478 rb.Push(lines);
488 } 479 }
489 480
490 cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
491
492 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); 481 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
493} 482}
494 483
495void SetTransferBytes(Service::Interface* self) { 484void SetTransferBytes(Service::Interface* self) {
496 u32* cmd_buff = Kernel::GetCommandBuffer(); 485 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0);
497 486 const PortSet port_select(rp.Pop<u8>());
498 const PortSet port_select(cmd_buff[1]); 487 const u16 transfer_bytes = rp.Pop<u16>();
499 const u32 transfer_bytes = cmd_buff[2] & 0xFFFF; 488 const u16 width = rp.Pop<u16>();
500 const u32 width = cmd_buff[3] & 0xFFFF; 489 const u16 height = rp.Pop<u16>();
501 const u32 height = cmd_buff[4] & 0xFFFF;
502 490
491 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
503 if (port_select.IsValid()) { 492 if (port_select.IsValid()) {
504 for (int i : port_select) { 493 for (int i : port_select) {
505 ports[i].transfer_bytes = transfer_bytes; 494 ports[i].transfer_bytes = transfer_bytes;
506 } 495 }
507 cmd_buff[1] = RESULT_SUCCESS.raw; 496 rb.Push(RESULT_SUCCESS);
508 } else { 497 } else {
509 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 498 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
510 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 499 rb.Push(ERROR_INVALID_ENUM_VALUE);
511 } 500 }
512 501
513 cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0);
514
515 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u", 502 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u",
516 port_select.m_val, transfer_bytes, width, height); 503 port_select.m_val, transfer_bytes, width, height);
517} 504}
518 505
519void GetTransferBytes(Service::Interface* self) { 506void GetTransferBytes(Service::Interface* self) {
520 u32* cmd_buff = Kernel::GetCommandBuffer(); 507 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0);
521 508 const PortSet port_select(rp.Pop<u8>());
522 const PortSet port_select(cmd_buff[1]);
523 509
510 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
524 if (port_select.IsSingle()) { 511 if (port_select.IsSingle()) {
525 int port = *port_select.begin(); 512 int port = *port_select.begin();
526 cmd_buff[1] = RESULT_SUCCESS.raw; 513 rb.Push(RESULT_SUCCESS);
527 cmd_buff[2] = ports[port].transfer_bytes; 514 rb.Push(ports[port].transfer_bytes);
528 } else { 515 } else {
529 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 516 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
530 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 517 rb.Push(ERROR_INVALID_ENUM_VALUE);
518 rb.Skip(1, false);
531 } 519 }
532 520
533 cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
534
535 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val); 521 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val);
536} 522}
537 523
538void GetMaxBytes(Service::Interface* self) { 524void GetMaxBytes(Service::Interface* self) {
539 u32* cmd_buff = Kernel::GetCommandBuffer(); 525 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0);
526 const u16 width = rp.Pop<u16>();
527 const u16 height = rp.Pop<u16>();
540 528
541 const u32 width = cmd_buff[1] & 0xFFFF; 529 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
542 const u32 height = cmd_buff[2] & 0xFFFF;
543 530
544 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 531 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
545 constexpr u32 MIN_TRANSFER_UNIT = 256; 532 constexpr u32 MIN_TRANSFER_UNIT = 256;
546 constexpr u32 MAX_BUFFER_SIZE = 2560; 533 constexpr u32 MAX_BUFFER_SIZE = 2560;
547 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { 534 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
548 cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; 535 rb.Push(ERROR_OUT_OF_RANGE);
536 rb.Skip(1, false);
549 } else { 537 } else {
550 u32 bytes = MAX_BUFFER_SIZE; 538 u32 bytes = MAX_BUFFER_SIZE;
551 539
@@ -553,63 +541,59 @@ void GetMaxBytes(Service::Interface* self) {
553 bytes -= MIN_TRANSFER_UNIT; 541 bytes -= MIN_TRANSFER_UNIT;
554 } 542 }
555 543
556 cmd_buff[1] = RESULT_SUCCESS.raw; 544 rb.Push(RESULT_SUCCESS);
557 cmd_buff[2] = bytes; 545 rb.Push(bytes);
558 } 546 }
559 cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0);
560 547
561 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); 548 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
562} 549}
563 550
564void SetTrimming(Service::Interface* self) { 551void SetTrimming(Service::Interface* self) {
565 u32* cmd_buff = Kernel::GetCommandBuffer(); 552 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0);
566 553 const PortSet port_select(rp.Pop<u8>());
567 const PortSet port_select(cmd_buff[1]); 554 const bool trim = rp.Pop<bool>();
568 const bool trim = (cmd_buff[2] & 0xFF) != 0;
569 555
556 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
570 if (port_select.IsValid()) { 557 if (port_select.IsValid()) {
571 for (int i : port_select) { 558 for (int i : port_select) {
572 ports[i].is_trimming = trim; 559 ports[i].is_trimming = trim;
573 } 560 }
574 cmd_buff[1] = RESULT_SUCCESS.raw; 561 rb.Push(RESULT_SUCCESS);
575 } else { 562 } else {
576 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 563 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
577 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 564 rb.Push(ERROR_INVALID_ENUM_VALUE);
578 } 565 }
579 566
580 cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0);
581
582 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim); 567 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim);
583} 568}
584 569
585void IsTrimming(Service::Interface* self) { 570void IsTrimming(Service::Interface* self) {
586 u32* cmd_buff = Kernel::GetCommandBuffer(); 571 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0);
587 572 const PortSet port_select(rp.Pop<u8>());
588 const PortSet port_select(cmd_buff[1]);
589 573
574 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
590 if (port_select.IsSingle()) { 575 if (port_select.IsSingle()) {
591 int port = *port_select.begin(); 576 int port = *port_select.begin();
592 cmd_buff[1] = RESULT_SUCCESS.raw; 577 rb.Push(RESULT_SUCCESS);
593 cmd_buff[2] = ports[port].is_trimming; 578 rb.Push(ports[port].is_trimming);
594 } else { 579 } else {
595 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 580 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
596 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 581 rb.Push(ERROR_INVALID_ENUM_VALUE);
582 rb.Skip(1, false);
597 } 583 }
598 584
599 cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
600
601 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 585 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
602} 586}
603 587
604void SetTrimmingParams(Service::Interface* self) { 588void SetTrimmingParams(Service::Interface* self) {
605 u32* cmd_buff = Kernel::GetCommandBuffer(); 589 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0);
606 590 const PortSet port_select(rp.Pop<u8>());
607 const PortSet port_select(cmd_buff[1]); 591 const u16 x0 = rp.Pop<u16>();
608 const u16 x0 = static_cast<u16>(cmd_buff[2] & 0xFFFF); 592 const u16 y0 = rp.Pop<u16>();
609 const u16 y0 = static_cast<u16>(cmd_buff[3] & 0xFFFF); 593 const u16 x1 = rp.Pop<u16>();
610 const u16 x1 = static_cast<u16>(cmd_buff[4] & 0xFFFF); 594 const u16 y1 = rp.Pop<u16>();
611 const u16 y1 = static_cast<u16>(cmd_buff[5] & 0xFFFF); 595
612 596 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
613 if (port_select.IsValid()) { 597 if (port_select.IsValid()) {
614 for (int i : port_select) { 598 for (int i : port_select) {
615 ports[i].x0 = x0; 599 ports[i].x0 = x0;
@@ -617,49 +601,46 @@ void SetTrimmingParams(Service::Interface* self) {
617 ports[i].x1 = x1; 601 ports[i].x1 = x1;
618 ports[i].y1 = y1; 602 ports[i].y1 = y1;
619 } 603 }
620 cmd_buff[1] = RESULT_SUCCESS.raw; 604 rb.Push(RESULT_SUCCESS);
621 } else { 605 } else {
622 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 606 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
623 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 607 rb.Push(ERROR_INVALID_ENUM_VALUE);
624 } 608 }
625 609
626 cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
627
628 LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val, 610 LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val,
629 x0, y0, x1, y1); 611 x0, y0, x1, y1);
630} 612}
631 613
632void GetTrimmingParams(Service::Interface* self) { 614void GetTrimmingParams(Service::Interface* self) {
633 u32* cmd_buff = Kernel::GetCommandBuffer(); 615 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0);
634 616 const PortSet port_select(rp.Pop<u8>());
635 const PortSet port_select(cmd_buff[1]);
636 617
618 IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
637 if (port_select.IsSingle()) { 619 if (port_select.IsSingle()) {
638 int port = *port_select.begin(); 620 int port = *port_select.begin();
639 cmd_buff[1] = RESULT_SUCCESS.raw; 621 rb.Push(RESULT_SUCCESS);
640 cmd_buff[2] = ports[port].x0; 622 rb.Push(ports[port].x0);
641 cmd_buff[3] = ports[port].y0; 623 rb.Push(ports[port].y0);
642 cmd_buff[4] = ports[port].x1; 624 rb.Push(ports[port].x1);
643 cmd_buff[5] = ports[port].y1; 625 rb.Push(ports[port].y1);
644 } else { 626 } else {
645 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 627 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
646 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 628 rb.Push(ERROR_INVALID_ENUM_VALUE);
629 rb.Skip(4, false);
647 } 630 }
648 631
649 cmd_buff[0] = IPC::MakeHeader(0x11, 5, 0);
650
651 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 632 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
652} 633}
653 634
654void SetTrimmingParamsCenter(Service::Interface* self) { 635void SetTrimmingParamsCenter(Service::Interface* self) {
655 u32* cmd_buff = Kernel::GetCommandBuffer(); 636 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0);
656 637 const PortSet port_select(rp.Pop<u8>());
657 const PortSet port_select(cmd_buff[1]); 638 const u16 trim_w = rp.Pop<u16>();
658 const u16 trim_w = static_cast<u16>(cmd_buff[2] & 0xFFFF); 639 const u16 trim_h = rp.Pop<u16>();
659 const u16 trim_h = static_cast<u16>(cmd_buff[3] & 0xFFFF); 640 const u16 cam_w = rp.Pop<u16>();
660 const u16 cam_w = static_cast<u16>(cmd_buff[4] & 0xFFFF); 641 const u16 cam_h = rp.Pop<u16>();
661 const u16 cam_h = static_cast<u16>(cmd_buff[5] & 0xFFFF); 642
662 643 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
663 if (port_select.IsValid()) { 644 if (port_select.IsValid()) {
664 for (int i : port_select) { 645 for (int i : port_select) {
665 ports[i].x0 = (cam_w - trim_w) / 2; 646 ports[i].x0 = (cam_w - trim_w) / 2;
@@ -667,23 +648,21 @@ void SetTrimmingParamsCenter(Service::Interface* self) {
667 ports[i].x1 = ports[i].x0 + trim_w; 648 ports[i].x1 = ports[i].x0 + trim_w;
668 ports[i].y1 = ports[i].y0 + trim_h; 649 ports[i].y1 = ports[i].y0 + trim_h;
669 } 650 }
670 cmd_buff[1] = RESULT_SUCCESS.raw; 651 rb.Push(RESULT_SUCCESS);
671 } else { 652 } else {
672 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 653 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
673 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 654 rb.Push(ERROR_INVALID_ENUM_VALUE);
674 } 655 }
675 656
676 cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
677
678 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u", 657 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u",
679 port_select.m_val, trim_w, trim_h, cam_w, cam_h); 658 port_select.m_val, trim_w, trim_h, cam_w, cam_h);
680} 659}
681 660
682void Activate(Service::Interface* self) { 661void Activate(Service::Interface* self) {
683 u32* cmd_buff = Kernel::GetCommandBuffer(); 662 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0);
684 663 const CameraSet camera_select(rp.Pop<u8>());
685 const CameraSet camera_select(cmd_buff[1]);
686 664
665 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
687 if (camera_select.IsValid()) { 666 if (camera_select.IsValid()) {
688 if (camera_select.m_val == 0) { // deactive all 667 if (camera_select.m_val == 0) { // deactive all
689 for (int i = 0; i < 2; ++i) { 668 for (int i = 0; i < 2; ++i) {
@@ -694,10 +673,10 @@ void Activate(Service::Interface* self) {
694 } 673 }
695 ports[i].is_active = false; 674 ports[i].is_active = false;
696 } 675 }
697 cmd_buff[1] = RESULT_SUCCESS.raw; 676 rb.Push(RESULT_SUCCESS);
698 } else if (camera_select[0] && camera_select[1]) { 677 } else if (camera_select[0] && camera_select[1]) {
699 LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated"); 678 LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated");
700 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 679 rb.Push(ERROR_INVALID_ENUM_VALUE);
701 } else { 680 } else {
702 if (camera_select[0]) { 681 if (camera_select[0]) {
703 ActivatePort(0, 0); 682 ActivatePort(0, 0);
@@ -708,24 +687,22 @@ void Activate(Service::Interface* self) {
708 if (camera_select[2]) { 687 if (camera_select[2]) {
709 ActivatePort(1, 2); 688 ActivatePort(1, 2);
710 } 689 }
711 cmd_buff[1] = RESULT_SUCCESS.raw; 690 rb.Push(RESULT_SUCCESS);
712 } 691 }
713 } else { 692 } else {
714 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); 693 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
715 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 694 rb.Push(ERROR_INVALID_ENUM_VALUE);
716 } 695 }
717 696
718 cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
719
720 LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val); 697 LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val);
721} 698}
722 699
723void SwitchContext(Service::Interface* self) { 700void SwitchContext(Service::Interface* self) {
724 u32* cmd_buff = Kernel::GetCommandBuffer(); 701 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0);
725 702 const CameraSet camera_select(rp.Pop<u8>());
726 const CameraSet camera_select(cmd_buff[1]); 703 const ContextSet context_select(rp.Pop<u8>());
727 const ContextSet context_select(cmd_buff[2]);
728 704
705 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
729 if (camera_select.IsValid() && context_select.IsSingle()) { 706 if (camera_select.IsValid() && context_select.IsSingle()) {
730 int context = *context_select.begin(); 707 int context = *context_select.begin();
731 for (int camera : camera_select) { 708 for (int camera : camera_select) {
@@ -736,26 +713,24 @@ void SwitchContext(Service::Interface* self) {
736 cameras[camera].impl->SetFormat(context_config.format); 713 cameras[camera].impl->SetFormat(context_config.format);
737 cameras[camera].impl->SetResolution(context_config.resolution); 714 cameras[camera].impl->SetResolution(context_config.resolution);
738 } 715 }
739 cmd_buff[1] = RESULT_SUCCESS.raw; 716 rb.Push(RESULT_SUCCESS);
740 } else { 717 } else {
741 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 718 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
742 context_select.m_val); 719 context_select.m_val);
743 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 720 rb.Push(ERROR_INVALID_ENUM_VALUE);
744 } 721 }
745 722
746 cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0);
747
748 LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val, 723 LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val,
749 context_select.m_val); 724 context_select.m_val);
750} 725}
751 726
752void FlipImage(Service::Interface* self) { 727void FlipImage(Service::Interface* self) {
753 u32* cmd_buff = Kernel::GetCommandBuffer(); 728 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0);
754 729 const CameraSet camera_select(rp.Pop<u8>());
755 const CameraSet camera_select(cmd_buff[1]); 730 const Flip flip = static_cast<Flip>(rp.Pop<u8>());
756 const Flip flip = static_cast<Flip>(cmd_buff[2] & 0xFF); 731 const ContextSet context_select(rp.Pop<u8>());
757 const ContextSet context_select(cmd_buff[3]);
758 732
733 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
759 if (camera_select.IsValid() && context_select.IsValid()) { 734 if (camera_select.IsValid() && context_select.IsValid()) {
760 for (int camera : camera_select) { 735 for (int camera : camera_select) {
761 for (int context : context_select) { 736 for (int context : context_select) {
@@ -765,32 +740,30 @@ void FlipImage(Service::Interface* self) {
765 } 740 }
766 } 741 }
767 } 742 }
768 cmd_buff[1] = RESULT_SUCCESS.raw; 743 rb.Push(RESULT_SUCCESS);
769 } else { 744 } else {
770 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 745 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
771 context_select.m_val); 746 context_select.m_val);
772 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 747 rb.Push(ERROR_INVALID_ENUM_VALUE);
773 } 748 }
774 749
775 cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0);
776
777 LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u", 750 LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u",
778 camera_select.m_val, static_cast<int>(flip), context_select.m_val); 751 camera_select.m_val, static_cast<int>(flip), context_select.m_val);
779} 752}
780 753
781void SetDetailSize(Service::Interface* self) { 754void SetDetailSize(Service::Interface* self) {
782 u32* cmd_buff = Kernel::GetCommandBuffer(); 755 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0);
783 756 const CameraSet camera_select(rp.Pop<u8>());
784 const CameraSet camera_select(cmd_buff[1]);
785 Resolution resolution; 757 Resolution resolution;
786 resolution.width = static_cast<u16>(cmd_buff[2] & 0xFFFF); 758 resolution.width = rp.Pop<u16>();
787 resolution.height = static_cast<u16>(cmd_buff[3] & 0xFFFF); 759 resolution.height = rp.Pop<u16>();
788 resolution.crop_x0 = static_cast<u16>(cmd_buff[4] & 0xFFFF); 760 resolution.crop_x0 = rp.Pop<u16>();
789 resolution.crop_y0 = static_cast<u16>(cmd_buff[5] & 0xFFFF); 761 resolution.crop_y0 = rp.Pop<u16>();
790 resolution.crop_x1 = static_cast<u16>(cmd_buff[6] & 0xFFFF); 762 resolution.crop_x1 = rp.Pop<u16>();
791 resolution.crop_y1 = static_cast<u16>(cmd_buff[7] & 0xFFFF); 763 resolution.crop_y1 = rp.Pop<u16>();
792 const ContextSet context_select(cmd_buff[8]); 764 const ContextSet context_select(rp.Pop<u8>());
793 765
766 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
794 if (camera_select.IsValid() && context_select.IsValid()) { 767 if (camera_select.IsValid() && context_select.IsValid()) {
795 for (int camera : camera_select) { 768 for (int camera : camera_select) {
796 for (int context : context_select) { 769 for (int context : context_select) {
@@ -800,15 +773,13 @@ void SetDetailSize(Service::Interface* self) {
800 } 773 }
801 } 774 }
802 } 775 }
803 cmd_buff[1] = RESULT_SUCCESS.raw; 776 rb.Push(RESULT_SUCCESS);
804 } else { 777 } else {
805 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 778 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
806 context_select.m_val); 779 context_select.m_val);
807 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 780 rb.Push(ERROR_INVALID_ENUM_VALUE);
808 } 781 }
809 782
810 cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0);
811
812 LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, " 783 LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, "
813 "crop_x1=%u, crop_y1=%u, context_select=%u", 784 "crop_x1=%u, crop_y1=%u, context_select=%u",
814 camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0, 785 camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0,
@@ -816,12 +787,12 @@ void SetDetailSize(Service::Interface* self) {
816} 787}
817 788
818void SetSize(Service::Interface* self) { 789void SetSize(Service::Interface* self) {
819 u32* cmd_buff = Kernel::GetCommandBuffer(); 790 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0);
820 791 const CameraSet camera_select(rp.Pop<u8>());
821 const CameraSet camera_select(cmd_buff[1]); 792 const u8 size = rp.Pop<u8>();
822 const u32 size = cmd_buff[2] & 0xFF; 793 const ContextSet context_select(rp.Pop<u8>());
823 const ContextSet context_select(cmd_buff[3]);
824 794
795 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
825 if (camera_select.IsValid() && context_select.IsValid()) { 796 if (camera_select.IsValid() && context_select.IsValid()) {
826 for (int camera : camera_select) { 797 for (int camera : camera_select) {
827 for (int context : context_select) { 798 for (int context : context_select) {
@@ -831,49 +802,45 @@ void SetSize(Service::Interface* self) {
831 } 802 }
832 } 803 }
833 } 804 }
834 cmd_buff[1] = RESULT_SUCCESS.raw; 805 rb.Push(RESULT_SUCCESS);
835 } else { 806 } else {
836 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 807 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
837 context_select.m_val); 808 context_select.m_val);
838 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 809 rb.Push(ERROR_INVALID_ENUM_VALUE);
839 } 810 }
840 811
841 cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0);
842
843 LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u", 812 LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u",
844 camera_select.m_val, size, context_select.m_val); 813 camera_select.m_val, size, context_select.m_val);
845} 814}
846 815
847void SetFrameRate(Service::Interface* self) { 816void SetFrameRate(Service::Interface* self) {
848 u32* cmd_buff = Kernel::GetCommandBuffer(); 817 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0);
849 818 const CameraSet camera_select(rp.Pop<u8>());
850 const CameraSet camera_select(cmd_buff[1]); 819 const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
851 const FrameRate frame_rate = static_cast<FrameRate>(cmd_buff[2] & 0xFF);
852 820
821 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
853 if (camera_select.IsValid()) { 822 if (camera_select.IsValid()) {
854 for (int camera : camera_select) { 823 for (int camera : camera_select) {
855 cameras[camera].frame_rate = frame_rate; 824 cameras[camera].frame_rate = frame_rate;
856 // TODO(wwylele): consider hinting the actual camera with the expected frame rate 825 // TODO(wwylele): consider hinting the actual camera with the expected frame rate
857 } 826 }
858 cmd_buff[1] = RESULT_SUCCESS.raw; 827 rb.Push(RESULT_SUCCESS);
859 } else { 828 } else {
860 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); 829 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
861 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 830 rb.Push(ERROR_INVALID_ENUM_VALUE);
862 } 831 }
863 832
864 cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
865
866 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d", 833 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d",
867 camera_select.m_val, static_cast<int>(frame_rate)); 834 camera_select.m_val, static_cast<int>(frame_rate));
868} 835}
869 836
870void SetEffect(Service::Interface* self) { 837void SetEffect(Service::Interface* self) {
871 u32* cmd_buff = Kernel::GetCommandBuffer(); 838 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0);
872 839 const CameraSet camera_select(rp.Pop<u8>());
873 const CameraSet camera_select(cmd_buff[1]); 840 const Effect effect = static_cast<Effect>(rp.Pop<u8>());
874 const Effect effect = static_cast<Effect>(cmd_buff[2] & 0xFF); 841 const ContextSet context_select(rp.Pop<u8>());
875 const ContextSet context_select(cmd_buff[3]);
876 842
843 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
877 if (camera_select.IsValid() && context_select.IsValid()) { 844 if (camera_select.IsValid() && context_select.IsValid()) {
878 for (int camera : camera_select) { 845 for (int camera : camera_select) {
879 for (int context : context_select) { 846 for (int context : context_select) {
@@ -883,26 +850,24 @@ void SetEffect(Service::Interface* self) {
883 } 850 }
884 } 851 }
885 } 852 }
886 cmd_buff[1] = RESULT_SUCCESS.raw; 853 rb.Push(RESULT_SUCCESS);
887 } else { 854 } else {
888 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 855 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
889 context_select.m_val); 856 context_select.m_val);
890 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 857 rb.Push(ERROR_INVALID_ENUM_VALUE);
891 } 858 }
892 859
893 cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0);
894
895 LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u", 860 LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u",
896 camera_select.m_val, static_cast<int>(effect), context_select.m_val); 861 camera_select.m_val, static_cast<int>(effect), context_select.m_val);
897} 862}
898 863
899void SetOutputFormat(Service::Interface* self) { 864void SetOutputFormat(Service::Interface* self) {
900 u32* cmd_buff = Kernel::GetCommandBuffer(); 865 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0);
901 866 const CameraSet camera_select(rp.Pop<u8>());
902 const CameraSet camera_select(cmd_buff[1]); 867 const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
903 const OutputFormat format = static_cast<OutputFormat>(cmd_buff[2] & 0xFF); 868 const ContextSet context_select(rp.Pop<u8>());
904 const ContextSet context_select(cmd_buff[3]);
905 869
870 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
906 if (camera_select.IsValid() && context_select.IsValid()) { 871 if (camera_select.IsValid() && context_select.IsValid()) {
907 for (int camera : camera_select) { 872 for (int camera : camera_select) {
908 for (int context : context_select) { 873 for (int context : context_select) {
@@ -912,34 +877,32 @@ void SetOutputFormat(Service::Interface* self) {
912 } 877 }
913 } 878 }
914 } 879 }
915 cmd_buff[1] = RESULT_SUCCESS.raw; 880 rb.Push(RESULT_SUCCESS);
916 } else { 881 } else {
917 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 882 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
918 context_select.m_val); 883 context_select.m_val);
919 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 884 rb.Push(ERROR_INVALID_ENUM_VALUE);
920 } 885 }
921 886
922 cmd_buff[0] = IPC::MakeHeader(0x25, 1, 0);
923
924 LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u", 887 LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u",
925 camera_select.m_val, static_cast<int>(format), context_select.m_val); 888 camera_select.m_val, static_cast<int>(format), context_select.m_val);
926} 889}
927 890
928void SynchronizeVsyncTiming(Service::Interface* self) { 891void SynchronizeVsyncTiming(Service::Interface* self) {
929 u32* cmd_buff = Kernel::GetCommandBuffer(); 892 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0);
893 const u8 camera_select1 = rp.Pop<u8>();
894 const u8 camera_select2 = rp.Pop<u8>();
930 895
931 const u32 camera_select1 = cmd_buff[1] & 0xFF; 896 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
932 const u32 camera_select2 = cmd_buff[2] & 0xFF; 897 rb.Push(RESULT_SUCCESS);
933
934 cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0);
935 cmd_buff[1] = RESULT_SUCCESS.raw;
936 898
937 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u", 899 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u",
938 camera_select1, camera_select2); 900 camera_select1, camera_select2);
939} 901}
940 902
941void GetStereoCameraCalibrationData(Service::Interface* self) { 903void GetStereoCameraCalibrationData(Service::Interface* self) {
942 u32* cmd_buff = Kernel::GetCommandBuffer(); 904 IPC::RequestBuilder rb =
905 IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0);
943 906
944 // Default values taken from yuriks' 3DS. Valid data is required here or games using the 907 // Default values taken from yuriks' 3DS. Valid data is required here or games using the
945 // calibration get stuck in an infinite CPU loop. 908 // calibration get stuck in an infinite CPU loop.
@@ -958,34 +921,28 @@ void GetStereoCameraCalibrationData(Service::Interface* self) {
958 data.imageWidth = 640; 921 data.imageWidth = 640;
959 data.imageHeight = 480; 922 data.imageHeight = 480;
960 923
961 cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0); 924 rb.Push(RESULT_SUCCESS);
962 cmd_buff[1] = RESULT_SUCCESS.raw; 925 rb.PushRaw(data);
963 memcpy(&cmd_buff[2], &data, sizeof(data));
964 926
965 LOG_TRACE(Service_CAM, "called"); 927 LOG_TRACE(Service_CAM, "called");
966} 928}
967 929
968void SetPackageParameterWithoutContext(Service::Interface* self) { 930void SetPackageParameterWithoutContext(Service::Interface* self) {
969 u32* cmd_buff = Kernel::GetCommandBuffer(); 931 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0);
970 932
971 PackageParameterWithoutContext package; 933 PackageParameterWithoutContext package;
972 std::memcpy(&package, cmd_buff + 1, sizeof(package)); 934 rp.PopRaw(package);
973 935
974 cmd_buff[0] = IPC::MakeHeader(0x33, 1, 0); 936 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
975 cmd_buff[1] = RESULT_SUCCESS.raw; 937 rb.Push(RESULT_SUCCESS);
976 938
977 LOG_WARNING(Service_CAM, "(STUBBED) called"); 939 LOG_WARNING(Service_CAM, "(STUBBED) called");
978} 940}
979 941
980template <typename PackageParameterType, int command_id> 942template <typename PackageParameterType>
981static void SetPackageParameter() { 943static ResultCode SetPackageParameter(const PackageParameterType& package) {
982 u32* cmd_buff = Kernel::GetCommandBuffer(); 944 const CameraSet camera_select(package.camera_select);
983 945 const ContextSet context_select(package.context_select);
984 PackageParameterType package;
985 std::memcpy(&package, cmd_buff + 1, sizeof(package));
986
987 const CameraSet camera_select(static_cast<u32>(package.camera_select));
988 const ContextSet context_select(static_cast<u32>(package.context_select));
989 946
990 if (camera_select.IsValid() && context_select.IsValid()) { 947 if (camera_select.IsValid() && context_select.IsValid()) {
991 for (int camera_id : camera_select) { 948 for (int camera_id : camera_select) {
@@ -1002,53 +959,66 @@ static void SetPackageParameter() {
1002 } 959 }
1003 } 960 }
1004 } 961 }
1005 cmd_buff[1] = RESULT_SUCCESS.raw; 962 return RESULT_SUCCESS;
1006 } else { 963 } else {
1007 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select, 964 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select,
1008 package.context_select); 965 package.context_select);
1009 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 966 return ERROR_INVALID_ENUM_VALUE;
1010 } 967 }
1011
1012 cmd_buff[0] = IPC::MakeHeader(command_id, 1, 0);
1013
1014 LOG_DEBUG(Service_CAM, "called");
1015} 968}
1016 969
1017Resolution PackageParameterWithContext::GetResolution() { 970Resolution PackageParameterWithContext::GetResolution() const {
1018 return PRESET_RESOLUTION[static_cast<int>(size)]; 971 return PRESET_RESOLUTION[static_cast<int>(size)];
1019} 972}
1020 973
1021void SetPackageParameterWithContext(Service::Interface* self) { 974void SetPackageParameterWithContext(Service::Interface* self) {
1022 SetPackageParameter<PackageParameterWithContext, 0x34>(); 975 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0);
976
977 PackageParameterWithContext package;
978 rp.PopRaw(package);
979
980 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
981 ResultCode result = SetPackageParameter(package);
982 rb.Push(result);
983
984 LOG_DEBUG(Service_CAM, "called");
1023} 985}
1024 986
1025void SetPackageParameterWithContextDetail(Service::Interface* self) { 987void SetPackageParameterWithContextDetail(Service::Interface* self) {
1026 SetPackageParameter<PackageParameterWithContextDetail, 0x35>(); 988 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0);
989
990 PackageParameterWithContextDetail package;
991 rp.PopRaw(package);
992
993 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
994 ResultCode result = SetPackageParameter(package);
995 rb.Push(result);
996
997 LOG_DEBUG(Service_CAM, "called");
1027} 998}
1028 999
1029void GetSuitableY2rStandardCoefficient(Service::Interface* self) { 1000void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
1030 u32* cmd_buff = Kernel::GetCommandBuffer(); 1001 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0);
1031 1002 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
1032 cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0); 1003 rb.Push(RESULT_SUCCESS);
1033 cmd_buff[1] = RESULT_SUCCESS.raw; 1004 rb.Push<u32>(0);
1034 cmd_buff[2] = 0;
1035 1005
1036 LOG_WARNING(Service_CAM, "(STUBBED) called"); 1006 LOG_WARNING(Service_CAM, "(STUBBED) called");
1037} 1007}
1038 1008
1039void PlayShutterSound(Service::Interface* self) { 1009void PlayShutterSound(Service::Interface* self) {
1040 u32* cmd_buff = Kernel::GetCommandBuffer(); 1010 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0);
1041 1011 u8 sound_id = rp.Pop<u8>();
1042 u8 sound_id = cmd_buff[1] & 0xFF;
1043 1012
1044 cmd_buff[0] = IPC::MakeHeader(0x38, 1, 0); 1013 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
1045 cmd_buff[1] = RESULT_SUCCESS.raw; 1014 rb.Push(RESULT_SUCCESS);
1046 1015
1047 LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); 1016 LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id);
1048} 1017}
1049 1018
1050void DriverInitialize(Service::Interface* self) { 1019void DriverInitialize(Service::Interface* self) {
1051 u32* cmd_buff = Kernel::GetCommandBuffer(); 1020 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0);
1021 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
1052 1022
1053 for (int camera_id = 0; camera_id < NumCameras; ++camera_id) { 1023 for (int camera_id = 0; camera_id < NumCameras; ++camera_id) {
1054 CameraConfig& camera = cameras[camera_id]; 1024 CameraConfig& camera = cameras[camera_id];
@@ -1074,14 +1044,14 @@ void DriverInitialize(Service::Interface* self) {
1074 port.Clear(); 1044 port.Clear();
1075 } 1045 }
1076 1046
1077 cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0); 1047 rb.Push(RESULT_SUCCESS);
1078 cmd_buff[1] = RESULT_SUCCESS.raw;
1079 1048
1080 LOG_DEBUG(Service_CAM, "called"); 1049 LOG_DEBUG(Service_CAM, "called");
1081} 1050}
1082 1051
1083void DriverFinalize(Service::Interface* self) { 1052void DriverFinalize(Service::Interface* self) {
1084 u32* cmd_buff = Kernel::GetCommandBuffer(); 1053 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0);
1054 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
1085 1055
1086 CancelReceiving(0); 1056 CancelReceiving(0);
1087 CancelReceiving(1); 1057 CancelReceiving(1);
@@ -1090,8 +1060,7 @@ void DriverFinalize(Service::Interface* self) {
1090 camera.impl = nullptr; 1060 camera.impl = nullptr;
1091 } 1061 }
1092 1062
1093 cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0); 1063 rb.Push(RESULT_SUCCESS);
1094 cmd_buff[1] = RESULT_SUCCESS.raw;
1095 1064
1096 LOG_DEBUG(Service_CAM, "called"); 1065 LOG_DEBUG(Service_CAM, "called");
1097} 1066}
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 34a9c8479..b6da721d8 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -184,9 +184,10 @@ struct PackageParameterWithoutContext {
184 s16 auto_white_balance_window_y; 184 s16 auto_white_balance_window_y;
185 s16 auto_white_balance_window_width; 185 s16 auto_white_balance_window_width;
186 s16 auto_white_balance_window_height; 186 s16 auto_white_balance_window_height;
187 INSERT_PADDING_WORDS(4);
187}; 188};
188 189
189static_assert(sizeof(PackageParameterWithoutContext) == 28, 190static_assert(sizeof(PackageParameterWithoutContext) == 44,
190 "PackageParameterCameraWithoutContext structure size is wrong"); 191 "PackageParameterCameraWithoutContext structure size is wrong");
191 192
192struct PackageParameterWithContext { 193struct PackageParameterWithContext {
@@ -196,11 +197,12 @@ struct PackageParameterWithContext {
196 Effect effect; 197 Effect effect;
197 Size size; 198 Size size;
198 INSERT_PADDING_BYTES(3); 199 INSERT_PADDING_BYTES(3);
200 INSERT_PADDING_WORDS(3);
199 201
200 Resolution GetResolution(); 202 Resolution GetResolution() const;
201}; 203};
202 204
203static_assert(sizeof(PackageParameterWithContext) == 8, 205static_assert(sizeof(PackageParameterWithContext) == 20,
204 "PackageParameterWithContext structure size is wrong"); 206 "PackageParameterWithContext structure size is wrong");
205 207
206struct PackageParameterWithContextDetail { 208struct PackageParameterWithContextDetail {
@@ -209,13 +211,14 @@ struct PackageParameterWithContextDetail {
209 Flip flip; 211 Flip flip;
210 Effect effect; 212 Effect effect;
211 Resolution resolution; 213 Resolution resolution;
214 INSERT_PADDING_WORDS(3);
212 215
213 Resolution GetResolution() { 216 Resolution GetResolution() const {
214 return resolution; 217 return resolution;
215 } 218 }
216}; 219};
217 220
218static_assert(sizeof(PackageParameterWithContextDetail) == 16, 221static_assert(sizeof(PackageParameterWithContextDetail) == 28,
219 "PackageParameterWithContextDetail structure size is wrong"); 222 "PackageParameterWithContextDetail structure size is wrong");
220 223
221/** 224/**