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