diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index eb05a235b5..a56e83cdf4 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2849,7 +2849,7 @@ void thread_ctrl::set_native_priority(int priority) if (int err = pthread_setschedparam(pthread_self(), policy, ¶m)) { - sig_log.error("pthraed_setschedparam() failed: %d", err); + sig_log.error("pthread_setschedparam() failed: %d", err); } #endif } diff --git a/Utilities/simple_ringbuf.cpp b/Utilities/simple_ringbuf.cpp index ff37b4b295..ea25b502f2 100644 --- a/Utilities/simple_ringbuf.cpp +++ b/Utilities/simple_ringbuf.cpp @@ -5,6 +5,34 @@ simple_ringbuf::simple_ringbuf(u32 size) set_buf_size(size); } +simple_ringbuf::simple_ringbuf(simple_ringbuf&& other) +{ + rw_ptr = other.rw_ptr.load(); + buf_size = other.buf_size; + buf = std::move(other.buf); + initialized = other.initialized.observe(); + + other.buf_size = 0; + other.rw_ptr = 0; + other.initialized = false; +} + +simple_ringbuf& simple_ringbuf::operator=(simple_ringbuf&& other) +{ + if (this == &other) return *this; + + rw_ptr = other.rw_ptr.load(); + buf_size = other.buf_size; + buf = std::move(other.buf); + initialized = other.initialized.observe(); + + other.buf_size = 0; + other.rw_ptr = 0; + other.initialized = false; + + return *this; +} + u32 simple_ringbuf::get_free_size() { const u64 _rw_ptr = rw_ptr; @@ -19,6 +47,11 @@ u32 simple_ringbuf::get_used_size() return buf_size - 1 - get_free_size(); } +u32 simple_ringbuf::get_total_size() +{ + return buf_size; +} + void simple_ringbuf::set_buf_size(u32 size) { ensure(size); diff --git a/Utilities/simple_ringbuf.h b/Utilities/simple_ringbuf.h index 368d1b0e89..11912eed86 100644 --- a/Utilities/simple_ringbuf.h +++ b/Utilities/simple_ringbuf.h @@ -19,8 +19,15 @@ public: simple_ringbuf() {}; simple_ringbuf(u32 size); + simple_ringbuf(const simple_ringbuf&) = delete; + simple_ringbuf& operator=(const simple_ringbuf&) = delete; + + simple_ringbuf(simple_ringbuf&& other); + simple_ringbuf& operator=(simple_ringbuf&& other); + u32 get_free_size(); u32 get_used_size(); + u32 get_total_size(); // Thread unsafe functions. void set_buf_size(u32 size); diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index f45e5edc7b..4163fe7e97 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1196,7 +1196,10 @@ void lv2_obj::sleep(cpu_thread& cpu, const u64 timeout) { vm::temporary_unlock(cpu); cpu_counter::remove(&cpu); - std::lock_guard{g_mutex}, sleep_unlocked(cpu, timeout); + { + std::lock_guard lock{g_mutex}; + sleep_unlocked(cpu, timeout); + } g_to_awake.clear(); } diff --git a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h index 445080c2f4..9d7b40125d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h +++ b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h @@ -3,6 +3,47 @@ #include "Emu/Memory/vm_ptr.h" #include "Emu/Cell/ErrorCodes.h" +enum : u32 +{ + SYS_RSXAUDIO_SERIAL_STREAM_CNT = 4, + SYS_RSXAUDIO_STREAM_SIZE = 1024, + SYS_RSXAUDIO_DATA_BLK_SIZE = 256, + + SYS_RSXAUDIO_RINGBUF_BLK_SZ_SERIAL = 0x1000, + SYS_RSXAUDIO_RINGBUF_BLK_SZ_SPDIF = 0x400, + + SYS_RSXAUDIO_RINGBUF_SZ = 16, + + SYS_RSXAUDIO_AVPORT_CNT = 5, + + SYS_RSXAUDIO_FREQ_BASE_384K = 384000, + SYS_RSXAUDIO_FREQ_BASE_352K = 352800, + + SYS_RSXAUDIO_PORT_SERIAL = 0, + SYS_RSXAUDIO_PORT_SPDIF_0 = 1, + SYS_RSXAUDIO_PORT_SPDIF_1 = 2, + SYS_RSXAUDIO_PORT_INVALID = 0xFF, + SYS_RSXAUDIO_PORT_CNT = 3, + + SYS_RSXAUDIO_SPDIF_CNT = 2, +}; + +enum class RsxaudioAvportIdx : u8 +{ + HDMI_0 = 0, + HDMI_1 = 1, + AVMULTI = 2, + SPDIF_0 = 3, + SPDIF_1 = 4, +}; + +enum class RsxaudioSampleSize : u8 +{ + _16BIT = 2, + _32BIT = 4, +}; + + // SysCalls error_code sys_rsxaudio_initialize(vm::ptr handle); diff --git a/rpcs3/Emu/Cell/lv2/sys_uart.cpp b/rpcs3/Emu/Cell/lv2/sys_uart.cpp index 98e3d4b8f8..ad844d992b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_uart.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_uart.cpp @@ -1,63 +1,616 @@ #include "stdafx.h" +#include "Emu/System.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/lv2/sys_sync.h" +#include "Emu/Cell/lv2/sys_rsxaudio.h" #include "sys_uart.h" LOG_CHANNEL(sys_uart); +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](UartAudioCtrlID value) + { + switch (value) + { + STR_CASE(UartAudioCtrlID::DAC_RESET); + STR_CASE(UartAudioCtrlID::DAC_DE_EMPHASIS); + STR_CASE(UartAudioCtrlID::AVCLK); + } + + return unknown; + }); +} + +struct av_init_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_av_init); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + vuart.av_cmd_ver = pkt->hdr.version; + vuart.hdmi_events_bitmask |= pkt->event_bit; + + if (pkt->event_bit & PS3AV_EVENT_BIT_UNK) + { + // 0 or 255, probably ps2 backwards compatibility (inverted) + const ps3av_pkt_av_init_reply reply = { 0 }; + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS, &reply, sizeof(ps3av_pkt_av_init_reply)); + return; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_fini_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_header); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + vuart.hdmi_events_bitmask = 0; + + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS); + } +}; + struct av_get_monitor_info_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_get_monitor_info); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + ps3av_get_monitor_info_reply cfg{}; + + if (pkt->avport == static_cast(UartAudioAvport::AVMULTI_0)) + { + cfg.avport = static_cast(UartAudioAvport::AVMULTI_0); + cfg.monitor_type = PS3AV_MONITOR_TYPE_AVMULTI; + cfg.res_60.res_bits = UINT32_MAX; + cfg.res_50.res_bits = UINT32_MAX; + cfg.res_vesa.res_bits = UINT32_MAX; + cfg.cs.rgb = PS3AV_CS_SUPPORTED; + cfg.cs.yuv444 = PS3AV_CS_SUPPORTED; + cfg.cs.yuv422 = PS3AV_CS_SUPPORTED; + cfg.speaker_info = 1; + cfg.num_of_audio_block = 1; + cfg.audio_info[0].sbit = 7; + cfg.audio_info[0].max_num_of_ch = 2; + cfg.audio_info[0].type = PS3AV_MON_INFO_AUDIO_TYPE_LPCM; + cfg.audio_info[0].fs = 127; + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS, &cfg, sizeof(ps3av_get_monitor_info_reply)); + } + else if (pkt->avport <= static_cast(UartAudioAvport::HDMI_1)) + { + if (pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SYSCON_COMMUNICATE_FAIL); + return; + } + + set_hdmi_display_cfg(vuart, cfg, static_cast(pkt->avport)); + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS, &cfg, sizeof(ps3av_get_monitor_info_reply) - 4); // Length is different for some reason + } + else + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + } + } + + static void set_hdmi_display_cfg(vuart_av_thread &vuart, ps3av_get_monitor_info_reply &cfg, u8 avport) + { + if (vuart.hdmi_behavior_mode != PS3AV_HDMI_BEHAVIOR_NORMAL && (vuart.hdmi_behavior_mode & PS3AV_HDMI_BEHAVIOR_EDID_PASS)) + { + cfg.monitor_type = vuart.hdmi_behavior_mode & PS3AV_HDMI_BEHAVIOR_DVI ? PS3AV_MONITOR_TYPE_DVI : PS3AV_MONITOR_TYPE_HDMI; + return; + } + + // Report maximum support + + static constexpr u8 mon_id[sizeof(cfg.monitor_id)] = { 0x4A, 0x13, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15 }; + static constexpr u8 mon_name[sizeof(cfg.monitor_name)] = { 'R', 'P', 'C', 'S', '3', ' ', 'V', 'i', 'r', 't', 'M', 'o', 'n', '\0', '\0', '\0' }; + static constexpr ps3av_info_audio audio_info[PS3AV_MON_INFO_AUDIO_BLK_MAX] = + { + { PS3AV_MON_INFO_AUDIO_TYPE_LPCM, 8, 0x7F, 0x07 }, + { PS3AV_MON_INFO_AUDIO_TYPE_AC3, 8, 0x7F, 0xFF }, + { PS3AV_MON_INFO_AUDIO_TYPE_AAC, 8, 0x7F, 0xFF }, + { PS3AV_MON_INFO_AUDIO_TYPE_DTS, 8, 0x7F, 0xFF }, + { PS3AV_MON_INFO_AUDIO_TYPE_DDP, 8, 0x7F, 0xFF }, + { PS3AV_MON_INFO_AUDIO_TYPE_DTS_HD, 8, 0x7F, 0xFF }, + { PS3AV_MON_INFO_AUDIO_TYPE_DOLBY_THD, 8, 0x7F, 0xFF }, + }; + + cfg.avport = avport; + memcpy(cfg.monitor_id, mon_id, sizeof(cfg.monitor_id)); + cfg.monitor_type = PS3AV_MONITOR_TYPE_HDMI; + memcpy(cfg.monitor_name, mon_name, sizeof(cfg.monitor_name)); + + const u32 native_res = [&]() + { + switch (g_cfg.video.resolution) + { + case video_resolution::_1080: + return PS3AV_RESBIT_1920x1080P; + case video_resolution::_1600x1080: + case video_resolution::_1440x1080: + case video_resolution::_1280x1080: + case video_resolution::_720: + return PS3AV_RESBIT_1280x720P; + default: + return PS3AV_RESBIT_720x480P; + } + }(); + + cfg.res_60.res_bits = UINT32_MAX; + cfg.res_60.native = native_res; + cfg.res_50.res_bits = UINT32_MAX; + cfg.res_50.native = native_res; + cfg.res_other.res_bits = UINT32_MAX; + cfg.res_vesa.res_bits = 1; // Always one mode at a time + + cfg.cs.rgb = PS3AV_CS_SUPPORTED | PS3AV_RGB_SELECTABLE_QAUNTIZATION_RANGE | PS3AV_12BIT_COLOR; + cfg.cs.yuv444 = PS3AV_CS_SUPPORTED | PS3AV_12BIT_COLOR; + cfg.cs.yuv422 = PS3AV_CS_SUPPORTED; + cfg.cs.colorimetry_data = PS3AV_COLORIMETRY_xvYCC_601 | PS3AV_COLORIMETRY_xvYCC_709 | PS3AV_COLORIMETRY_MD0 | PS3AV_COLORIMETRY_MD1 | PS3AV_COLORIMETRY_MD2; + + cfg.color.red_x = 1023; + cfg.color.red_y = 0; + cfg.color.green_x = 0; + cfg.color.green_y = 1023; + cfg.color.blue_x = 0; + cfg.color.blue_y = 0; + cfg.color.white_x = 341; + cfg.color.white_y = 341; + cfg.color.gamma = 100; + + cfg.supported_ai = 1; + cfg.speaker_info = 0x4F; + + // Audio formats + cfg.num_of_audio_block = 7; + memcpy(cfg.audio_info, audio_info, sizeof(cfg.audio_info)); + + // 16:9 27-inch (as a default) + cfg.hor_screen_size = 60; + cfg.ver_screen_size = 34; + + cfg.supported_content_types = 0b1111; // Graphics, cinema, photo, game + + // 3D modes, no native formats + cfg.res_60_packed_3D.res_bits = UINT32_MAX; + cfg.res_50_packed_3D.res_bits = UINT32_MAX; + cfg.res_other_3D.res_bits = UINT32_MAX; + cfg.res_60_sbs_3D.res_bits = UINT32_MAX; + cfg.res_50_sbs_3D.res_bits = UINT32_MAX; + + cfg.vendor_specific_flags = 0; // values from 0-3 (unk) + } +}; + +struct av_get_bksv_list_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_get_bksv); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->avport > static_cast(UartAudioAvport::HDMI_1)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + return; + } + + if (pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SYSCON_COMMUNICATE_FAIL); + return; + } + + ps3av_pkt_get_bksv_reply reply{}; + reply.avport = pkt->avport; + u16 pkt_size = offsetof(ps3av_pkt_get_bksv_reply, ksv_arr); + + if (vuart.hdmi_behavior_mode == PS3AV_HDMI_BEHAVIOR_NORMAL || !(vuart.hdmi_behavior_mode & PS3AV_HDMI_BEHAVIOR_HDCP_OFF)) + { + reply.ksv_cnt = 1; + memcpy(reply.ksv_arr[0], PS3AV_BKSV_VALUE, sizeof(PS3AV_BKSV_VALUE)); + pkt_size = (pkt_size + 5 * reply.ksv_cnt + 3) & 0xFFFC; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS, &reply, pkt_size); + } +}; + +struct av_enable_event_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_enable_event); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + vuart.hdmi_events_bitmask |= pkt->event_bit; + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_disable_event_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_enable_event); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + vuart.hdmi_events_bitmask &= ~pkt->event_bit; + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_tv_mute_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_av_audio_mute); + } + + // Behavior is unknown, but it seems that this pkt could be ignored + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->avport < (g_cfg.core.debug_console_mode ? 2 : 1)) + { + sys_uart.notice("[av_tv_mute_cmd] tv mute set to %u", pkt->mute > 0); + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_null_cmd : public ps3av_cmd { u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override { return 12; } - bool execute(vuart_av_thread &vuart, const void *pkt_buf, u32 reply_max_size) override + void execute(vuart_av_thread &vuart, const void *pkt_buf) override { - auto pkt = static_cast(pkt_buf); + const auto pkt = static_cast(pkt_buf); - if (reply_max_size < sizeof(ps3av_get_monitor_info)) + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) { - vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); - return false; + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; } - // TODO: - auto evnt = std::make_unique(); - evnt->avport = 0; - // evnt->monitor_id = - evnt->monitor_type = PS3AV_MONITOR_TYPE_HDMI; + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS); + } +}; - // evnt->monitor_name; - evnt->res_60.native = PS3AV_RESBIT_1280x720P; - evnt->res_60.res_bits = 0xf; - evnt->res_50.native = PS3AV_RESBIT_1280x720P; - evnt->res_50.res_bits = 0xf; - evnt->res_vesa.res_bits = 1; +struct av_get_aksv_list_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_header); + } - evnt->cs.rgb = 1; - evnt->cs.yuv444 = 1; - evnt->cs.yuv422 = 1; + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); - evnt->color.blue_x = 0xFFFF; - evnt->color.blue_y = 0xFFFF; - evnt->color.green_x = 0xFFFF; - evnt->color.green_y = 0xFFFF; - evnt->color.red_x = 0xFFFF; - evnt->color.red_y = 0xFFFF; - evnt->color.white_x = 0xFFFF; - evnt->color.white_y = 0xFFFF; - evnt->color.gamma = 100; + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr) + sizeof(ps3av_pkt_get_aksv_reply)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } - evnt->supported_ai = 0; - evnt->speaker_info = 0; - evnt->num_of_audio_block = 0; + ps3av_pkt_get_aksv_reply reply{}; + memcpy(reply.ksv_arr[0], PS3AV_AKSV_VALUE, sizeof(PS3AV_AKSV_VALUE)); - vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS, evnt.get(), sizeof(ps3av_get_monitor_info_reply)); - return true; + if (g_cfg.core.debug_console_mode) + { + memcpy(reply.ksv_arr[1], PS3AV_AKSV_VALUE, sizeof(PS3AV_AKSV_VALUE)); + reply.ksv_size = 2 * sizeof(PS3AV_AKSV_VALUE); + } + else + { + reply.ksv_size = sizeof(PS3AV_AKSV_VALUE); + } + + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS, &reply, sizeof(ps3av_pkt_get_aksv_reply)); + } +}; + +struct video_disable_signal_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_video_disable_sig); + } + + // Cross color reduction filter setting in vsh. (AVMULTI) + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->avport <= static_cast(UartAudioAvport::HDMI_1)) + { + // TBA + + if (pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SYSCON_COMMUNICATE_FAIL); + return; + } + + vuart.hdmi_res_set[pkt->avport == static_cast(UartAudioAvport::HDMI_1)] = false; + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } + else if (pkt->avport == static_cast(UartAudioAvport::AVMULTI_0)) + { + if (vuart.head_b_initialized) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } + } + else + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } + } +}; + +struct av_video_ytrapcontrol_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_av_video_ytrapcontrol); + } + + // Cross color reduction filter setting in vsh. (AVMULTI) + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_get_hw_info_reply) + sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->unk1 && pkt->unk1 != 5U) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + return; + } + + sys_uart.notice("[av_video_ytrapcontrol_cmd] unk1=0x%04x unk2=0x%04x", pkt->unk1, pkt->unk2); + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_audio_mute_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_av_audio_mute); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (pkt->avport == static_cast(UartAudioAvport::AVMULTI_1)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + return; + } + + if ((pkt->avport > static_cast(UartAudioAvport::HDMI_1) && pkt->avport != static_cast(UartAudioAvport::AVMULTI_0)) || + (pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SYSCON_COMMUNICATE_FAIL); + return; + } + + // TBA + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_acp_ctrl_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_acp_ctrl); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (pkt->avport > static_cast(UartAudioAvport::HDMI_1) || + (pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + return; + } + + sys_uart.notice("[av_acp_ctrl_cmd] HDMI_%u data island ctrl pkt ctrl=0x%02x", pkt->avport, pkt->packetctl); + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_set_acp_packet_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_set_acp_packet); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (pkt->avport > static_cast(UartAudioAvport::HDMI_1) || + (pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode) || + (pkt->pkt_type > 0x0A && pkt->pkt_type < 0x81) || + pkt->pkt_type > 0x85) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + return; + } + + sys_uart.notice("[av_set_acp_packet_cmd] HDMI_%u data island pkt type=0x%02x", pkt->avport, pkt->pkt_type); + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_add_signal_ctl_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_add_signal_ctl); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->avport != static_cast(UartAudioAvport::AVMULTI_0)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + return; + } + + sys_uart.notice("[av_add_signal_ctl_cmd] signal_ctl=0x%04x", pkt->signal_ctl); + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_set_cgms_wss_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_av_set_cgms_wss); + } + + // Something related to copy control on AVMULTI. + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->avport != static_cast(UartAudioAvport::AVMULTI_0)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_PORT); + return; + } + + sys_uart.notice("[av_set_cgms_wss_cmd] cgms_wss=0x%08x", pkt->cgms_wss); + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); } }; @@ -65,31 +618,876 @@ struct av_get_hw_conf_cmd : public ps3av_cmd { u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override { - return 8; + return sizeof(ps3av_header); } - bool execute(vuart_av_thread &vuart, const void *pkt_buf, u32 reply_max_size) override + void execute(vuart_av_thread &vuart, const void *pkt_buf) override { - auto pkt = static_cast(pkt_buf); + const auto pkt = static_cast(pkt_buf); - if (reply_max_size < sizeof(ps3av_get_hw_info_reply) + sizeof(ps3av_pkt_reply_hdr)) + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_get_hw_info_reply) + sizeof(ps3av_pkt_reply_hdr)) { vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); - return false; + return; } - // TODO: - auto out = std::make_unique(); - out->num_of_hdmi = 1; - out->num_of_avmulti = 0; - out->num_of_spdif = 1; - out->resv = 0; + ps3av_get_hw_info_reply out{}; + out.num_of_hdmi = g_cfg.core.debug_console_mode ? 2 : 1; + out.num_of_avmulti = 1; + out.num_of_spdif = 1; + out.extra_bistream_support = 1; + + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS, &out, sizeof(ps3av_get_hw_info_reply)); + } +}; + +struct av_set_hdmi_mode_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_set_hdmi_mode); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (pkt->mode != PS3AV_HDMI_BEHAVIOR_NORMAL) + { + if ((pkt->mode & PS3AV_HDMI_BEHAVIOR_HDCP_OFF) && !g_cfg.core.debug_console_mode) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_UNSUPPORTED_HDMI_MODE); + return; + } + + if (pkt->mode & ~(PS3AV_HDMI_BEHAVIOR_HDCP_OFF | PS3AV_HDMI_BEHAVIOR_EDID_PASS | PS3AV_HDMI_BEHAVIOR_DVI)) + { + sys_uart.warning("[av_set_hdmi_mode_cmd] Unknown bits in hdmi mode: 0x%02x", pkt->mode); + } + } + + vuart.hdmi_behavior_mode = pkt->mode; + + vuart.add_hdmi_events(UartHdmiEvent::UNPLUGGED, vuart.hdmi_res_set[0] ? UartHdmiEvent::HDCP_DONE : UartHdmiEvent::PLUGGED, true, false); + vuart.add_hdmi_events(UartHdmiEvent::UNPLUGGED, vuart.hdmi_res_set[1] ? UartHdmiEvent::HDCP_DONE : UartHdmiEvent::PLUGGED, false, true); + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct av_get_cec_status_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_header); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_av_get_cec_config_reply) + sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + const ps3av_pkt_av_get_cec_config_reply reply{1}; + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS, &reply, sizeof(ps3av_pkt_av_get_cec_config_reply)); + } +}; + +struct video_init_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_header); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct video_set_format_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_video_format); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->video_head > PS3AV_HEAD_B_ANALOG || pkt->video_order > 1 || pkt->video_format > 16) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_VIDEO_PARAM); + return; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct video_set_route_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return 24; + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + vuart.write_resp(pkt->cid, PS3AV_STATUS_NO_SEL); // Only available in PS2_GX_LPAR + } +}; + +struct video_set_pitch_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_video_set_pitch); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (pkt->video_head > PS3AV_HEAD_B_ANALOG || (pkt->pitch & 7) != 0U || pkt->pitch > UINT16_MAX) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_VIDEO_PARAM); + return; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct video_get_hw_cfg_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_header); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_video_get_hw_cfg_reply) + sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + ps3av_pkt_video_get_hw_cfg_reply reply{}; + reply.gx_available = 0; // Set to 1 only in PS2_GX_LPAR + + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS, &reply, sizeof(ps3av_pkt_video_get_hw_cfg_reply)); + } +}; + +struct audio_init_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_header); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + // TBA + + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct audio_set_mode_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_audio_mode); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + if (!set_mode(*pkt)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_INVALID_AUDIO_PARAM); + } + else + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } + } + +private: + + bool set_mode(const ps3av_pkt_audio_mode& pkt) + { + bool spdif_use_serial_buf = false; + u8 avport_src, rsxaudio_port; + RsxaudioAvportIdx avport_idx; + + switch (pkt.avport) + { + case UartAudioAvport::HDMI_0: + { + avport_idx = RsxaudioAvportIdx::HDMI_0; + if (pkt.audio_source == UartAudioSource::SPDIF) + { + avport_src = rsxaudio_port = SYS_RSXAUDIO_PORT_SPDIF_1; + } + else + { + avport_src = rsxaudio_port = SYS_RSXAUDIO_PORT_SERIAL; + } + break; + } + case UartAudioAvport::HDMI_1: + { + avport_idx = RsxaudioAvportIdx::HDMI_1; + if (pkt.audio_source == UartAudioSource::SPDIF) + { + avport_src = rsxaudio_port = SYS_RSXAUDIO_PORT_SPDIF_1; + } + else + { + avport_src = rsxaudio_port = SYS_RSXAUDIO_PORT_SERIAL; + } + break; + } + case UartAudioAvport::AVMULTI_0: + { + avport_idx = RsxaudioAvportIdx::AVMULTI; + avport_src = rsxaudio_port = SYS_RSXAUDIO_PORT_SERIAL; + break; + } + case UartAudioAvport::SPDIF_0: + { + avport_idx = RsxaudioAvportIdx::SPDIF_0; + rsxaudio_port = SYS_RSXAUDIO_PORT_SPDIF_0; + if (pkt.audio_source == UartAudioSource::SERIAL) + { + spdif_use_serial_buf = true; + avport_src = SYS_RSXAUDIO_PORT_SERIAL; + } + else + { + avport_src = SYS_RSXAUDIO_PORT_SPDIF_0; + } + + break; + } + case UartAudioAvport::SPDIF_1: + { + avport_idx = RsxaudioAvportIdx::SPDIF_1; + rsxaudio_port = SYS_RSXAUDIO_PORT_SPDIF_1; + if (pkt.audio_source == UartAudioSource::SERIAL) + { + spdif_use_serial_buf = true; + avport_src = SYS_RSXAUDIO_PORT_SERIAL; + } + else + { + avport_src = SYS_RSXAUDIO_PORT_SPDIF_1; + } + + break; + } + default: + { + return false; + } + } + + const u32 freq = [&]() + { + switch (pkt.audio_fs) + { + case UartAudioFreq::_44K: return 44100; + case UartAudioFreq::_48K: return 48000; + case UartAudioFreq::_88K: return 88200; + case UartAudioFreq::_96K: return 96000; + case UartAudioFreq::_176K: return 176400; + case UartAudioFreq::_192K: return 192000; + default: return 0; + } + }(); + + if (freq == 0) return false; + + const auto bit_cnt = [&]() + { + if ((rsxaudio_port != SYS_RSXAUDIO_PORT_SERIAL && pkt.audio_format != UartAudioFormat::PCM) || + pkt.audio_word_bits == UartAudioSampleSize::_16BIT) + { + return UartAudioSampleSize::_16BIT; + } + else + { + return UartAudioSampleSize::_24BIT; + } + }(); + + return commit_param(rsxaudio_port, avport_idx, avport_src, freq, bit_cnt, spdif_use_serial_buf, pkt.audio_cs_info); + } + + bool commit_param(u8 rsxaudio_port, RsxaudioAvportIdx avport, u8 avport_src, u32 freq, + UartAudioSampleSize bit_cnt, bool spdif_use_serial_buf, const u8 *cs_data) + { + // TBA + const auto avport_idx = static_cast>(avport); + const auto rsxaudio_word_depth = bit_cnt == UartAudioSampleSize::_16BIT ? RsxaudioSampleSize::_16BIT : RsxaudioSampleSize::_32BIT; + + switch (rsxaudio_port) + { + case SYS_RSXAUDIO_PORT_SERIAL: + { + // TBA + break; + } + case SYS_RSXAUDIO_PORT_SPDIF_0: + case SYS_RSXAUDIO_PORT_SPDIF_1: + { + const u8 spdif_idx = rsxaudio_port == SYS_RSXAUDIO_PORT_SPDIF_1; + + // TBA + break; + } + default: + { + return false; + } + } - vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS, out.get(), sizeof(ps3av_get_hw_info_reply)); return true; } }; +struct audio_mute_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + // From RE + return 0; + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + switch (pkt->avport) + { + case UartAudioAvport::HDMI_0: + case UartAudioAvport::HDMI_1: + case UartAudioAvport::AVMULTI_0: + case UartAudioAvport::AVMULTI_1: + // TBA + break; + case UartAudioAvport::SPDIF_0: + // TBA + break; + case UartAudioAvport::SPDIF_1: + // TBA + break; + default: + break; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct audio_set_active_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_audio_set_active); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + const bool requested_avports[SYS_RSXAUDIO_AVPORT_CNT] = + { + (pkt->audio_port & PS3AV_AUDIO_PORT_HDMI_0) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_HDMI_1) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_AVMULTI) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_SPDIF_0) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_SPDIF_1) != 0U + }; + + // TBA + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct audio_set_inactive_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_audio_set_active); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + // TBA + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct audio_spdif_bit_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_audio_spdif_bit); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + const bool requested_avports[SYS_RSXAUDIO_AVPORT_CNT] = + { + (pkt->audio_port & PS3AV_AUDIO_PORT_HDMI_0) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_HDMI_1) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_AVMULTI) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_SPDIF_0) != 0U, + (pkt->audio_port & PS3AV_AUDIO_PORT_SPDIF_1) != 0U + }; + + // TBA + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct audio_ctrl_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override + { + return sizeof(ps3av_pkt_audio_ctrl); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + switch (pkt->audio_ctrl_id) + { + case UartAudioCtrlID::DAC_RESET: + case UartAudioCtrlID::DAC_DE_EMPHASIS: + case UartAudioCtrlID::AVCLK: + sys_uart.notice("[audio_ctrl_cmd] Option 0x%x", pkt->audio_ctrl_id); + break; + default: + break; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } +}; + +struct inc_avset_cmd : public ps3av_cmd +{ + u16 get_size(vuart_av_thread& /*vuart*/, const void* pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + + if (pkt->num_of_video_pkt > 2 || pkt->num_of_av_video_pkt > 4 || pkt->num_of_av_audio_pkt > 4) + { + return -1; + } + + const auto data_start = static_cast(pkt_buf) + sizeof(ps3av_pkt_inc_avset); + + u64 video_pkt_sec_size = 0; + u64 av_video_pkt_sec_size = 0; + u64 av_audio_pkt_sec_size = 0; + + for (u16 pkt_idx = 0; pkt_idx < pkt->num_of_video_pkt; pkt_idx++) + { + video_pkt_sec_size += reinterpret_cast(&data_start[video_pkt_sec_size])->length + 4ULL; + } + + for (u16 pkt_idx = 0; pkt_idx < pkt->num_of_av_video_pkt; pkt_idx++) + { + av_video_pkt_sec_size += reinterpret_cast(&data_start[video_pkt_sec_size + av_video_pkt_sec_size])->length + 4ULL; + } + + for (u16 pkt_idx = 0; pkt_idx < pkt->num_of_av_audio_pkt; pkt_idx++) + { + av_audio_pkt_sec_size += reinterpret_cast(&data_start[video_pkt_sec_size + av_video_pkt_sec_size + av_audio_pkt_sec_size])->length + 4ULL; + } + + return static_cast(sizeof(ps3av_pkt_inc_avset) + video_pkt_sec_size + av_video_pkt_sec_size + av_audio_pkt_sec_size); + } + + void execute(vuart_av_thread &vuart, const void *pkt_buf) override + { + const auto pkt = static_cast(pkt_buf); + auto pkt_data_addr = static_cast(pkt_buf) + sizeof(ps3av_pkt_inc_avset); + + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_BUFFER_OVERFLOW); + return; + } + + bool syscon_check_passed = true; + + // Video + u32 video_cmd_status = PS3AV_STATUS_SUCCESS; + for (u32 video_pkt_idx = 0; video_pkt_idx < pkt->num_of_video_pkt; ++video_pkt_idx) + { + const auto video_pkt = reinterpret_cast(pkt_data_addr); + const u32 subcmd_status = video_pkt_parse(*video_pkt); + + if (video_pkt->video_head == PS3AV_HEAD_B_ANALOG) + { + vuart.head_b_initialized = true; + } + + if (subcmd_status != PS3AV_STATUS_SUCCESS) + { + video_cmd_status = subcmd_status; + } + + pkt_data_addr += video_pkt->hdr.length + 4ULL; + } + + if (pkt->num_of_av_video_pkt == 0U && pkt->num_of_av_audio_pkt == 0U) + { + vuart.write_resp(pkt->hdr.cid, video_cmd_status); + return; + } + + u8 hdcp_done_cnt[2]{}; + + // AV Video + for (u32 video_av_pkt_idx = 0; video_av_pkt_idx < pkt->num_of_av_video_pkt; video_av_pkt_idx++) + { + const auto av_video_pkt = reinterpret_cast(pkt_data_addr); + const av_video_resp subcmd_resp = av_video_pkt_parse(*av_video_pkt, syscon_check_passed); + + if (subcmd_resp.status != PS3AV_STATUS_SUCCESS) + { + vuart.write_resp(pkt->hdr.cid, subcmd_resp.status); + return; + } + + if (syscon_check_passed) + { + if (subcmd_resp.hdcp_done_event[0]) hdcp_done_cnt[0]++; + if (subcmd_resp.hdcp_done_event[1]) hdcp_done_cnt[1]++; + } + + pkt_data_addr += av_video_pkt->hdr.length + 4ULL; + } + + while (hdcp_done_cnt[0] || hdcp_done_cnt[1]) + { + vuart.hdmi_res_set[0] = hdcp_done_cnt[0] > 0; + vuart.hdmi_res_set[1] = hdcp_done_cnt[1] > 0; + vuart.add_hdmi_events(UartHdmiEvent::HDCP_DONE, vuart.hdmi_res_set[0], vuart.hdmi_res_set[1]); + + if (hdcp_done_cnt[0]) + { + // TBA + hdcp_done_cnt[0]--; + } + if (hdcp_done_cnt[1]) + { + // TBA + hdcp_done_cnt[1]--; + } + } + + bool valid_av_audio_pkt = false; + + // AV Audio + for (u32 audio_av_pkt_idx = 0; audio_av_pkt_idx < pkt->num_of_av_audio_pkt; audio_av_pkt_idx++) + { + const auto av_audio_pkt = reinterpret_cast(pkt_data_addr); + + if (av_audio_pkt->avport <= static_cast(UartAudioAvport::HDMI_1)) + { + valid_av_audio_pkt = true; + + if (!syscon_check_passed || (av_audio_pkt->avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode)) + { + syscon_check_passed = false; + break; + } + + const u8 hdmi_idx = av_audio_pkt->avport == static_cast(UartAudioAvport::HDMI_1); + + // TBA + } + + pkt_data_addr += av_audio_pkt->hdr.length + 4ULL; + } + + if (pkt->num_of_av_video_pkt || valid_av_audio_pkt) + { + if (!syscon_check_passed) + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SYSCON_COMMUNICATE_FAIL); + return; + } + + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } + else + { + vuart.write_resp(pkt->hdr.cid, PS3AV_STATUS_SUCCESS); + } + } + +private: + + struct video_sce_param + { + u32 width_div; + u32 width; + u32 height; + }; + + struct av_video_resp + { + u32 status = PS3AV_STATUS_SUCCESS; + bool hdcp_done_event[2]{}; + }; + + u32 video_pkt_parse(const ps3av_pkt_video_mode &video_head_cfg) + { + constexpr video_sce_param sce_param_arr[28] = + { + { 0, 0, 0 }, + { 4, 2880, 480 }, + { 4, 2880, 480 }, + { 4, 2880, 576 }, + { 4, 2880, 576 }, + { 2, 1440, 480 }, + { 2, 1440, 576 }, + { 1, 1920, 1080 }, + { 1, 1920, 1080 }, + { 1, 1920, 1080 }, + { 1, 1280, 720 }, + { 1, 1280, 720 }, + { 1, 1920, 1080 }, + { 1, 1920, 1080 }, + { 1, 1920, 1080 }, + { 1, 1920, 1080 }, + { 1, 1280, 768 }, + { 1, 1280, 1024 }, + { 1, 1920, 1200 }, + { 1, 1360, 768 }, + { 1, 1280, 1470 }, + { 1, 1280, 1470 }, + { 1, 1920, 1080 }, + { 1, 1920, 2205 }, + { 1, 1920, 2205 }, + { 1, 1280, 721 }, + { 1, 720, 481 }, + { 1, 720, 577 } + }; + + const auto sce_idx = [&]() -> u8 + { + switch (video_head_cfg.video_vid) + { + case 16: return 1; + case 1: return 2; + case 3: return 4; + case 17: return 4; + case 5: return 5; + case 6: return 6; + case 18: return 7; + case 7: return 8; + case 33: return 8; + case 8: return 9; + case 34: return 9; + case 9: return 10; + case 31: return 10; + case 10: return 11; + case 32: return 11; + case 11: return 12; + case 35: return 12; + case 37: return 12; + case 12: return 13; + case 36: return 13; + case 38: return 13; + case 19: return 14; + case 20: return 15; + case 13: return 16; + case 14: return 17; + case 15: return 18; + case 21: return 19; + case 22: return 20; + case 27: return 20; + case 23: return 21; + case 28: return 21; + case 24: return 22; + case 25: return 23; + case 29: return 23; + case 26: return 24; + case 30: return 24; + case 39: return 25; + case 40: return 26; + case 41: return 27; + default: return umax; + } + }(); + + const video_sce_param &sce_param = sce_param_arr[sce_idx]; + if (sce_idx == umax || + video_head_cfg.video_head > PS3AV_HEAD_B_ANALOG || + video_head_cfg.video_order > 1 || + video_head_cfg.video_format > 16 || + video_head_cfg.video_out_format > 16 || + ((1ULL << video_head_cfg.video_out_format) & 0x1CE07) == 0U || + video_head_cfg.unk2 > 3 || + video_head_cfg.pitch & 7 || + video_head_cfg.pitch >> 16 || + (video_head_cfg.width != 1280U && ((video_head_cfg.width & 7) != 0U || video_head_cfg.width > UINT16_MAX)) || + (sce_param.width != 720 && video_head_cfg.width > sce_param.width / sce_param.width_div) || + !((video_head_cfg.height == 1470U && (sce_param.height == 721 || sce_param.height == 481 || sce_param.height == 577)) || (video_head_cfg.height <= sce_param.height && video_head_cfg.height <= UINT16_MAX))) + { + return PS3AV_STATUS_INVALID_VIDEO_PARAM; + } + + sys_uart.notice("[inc_avset_cmd] new resolution on HEAD_%c width=%u height=%u", video_head_cfg.video_head == PS3AV_HEAD_A_HDMI ? 'A' : 'B', video_head_cfg.width, video_head_cfg.height); + + return PS3AV_STATUS_SUCCESS; + } + + av_video_resp av_video_pkt_parse(const ps3av_pkt_av_video_cs &pkt, bool &syscon_pkt_valid) + { + if (pkt.avport <= static_cast(UartAudioAvport::HDMI_1)) + { + if (pkt.av_vid > 23) + { + return {PS3AV_STATUS_INVALID_AV_PARAM}; + } + + if (pkt.avport == static_cast(UartAudioAvport::HDMI_1) && !g_cfg.core.debug_console_mode) + { + syscon_pkt_valid = false; + } + else if (syscon_pkt_valid) + { + // HDMI setup, code 0x80 + + av_video_resp resp{}; + resp.hdcp_done_event[pkt.avport] = true; + return resp; + } + } + else + { + if ((pkt.avport != static_cast(UartAudioAvport::AVMULTI_0) && pkt.avport != static_cast(UartAudioAvport::AVMULTI_1)) || + pkt.av_vid > 23 || + (pkt.av_vid > 12 && pkt.av_vid != 18U)) + { + return {PS3AV_STATUS_INVALID_AV_PARAM}; + } + + if (pkt.avport == static_cast(UartAudioAvport::AVMULTI_1)) + { + syscon_pkt_valid = false; + } + else if (syscon_pkt_valid) + { + // AVMULTI setup + } + } + + return {}; + } +}; + struct generic_reply_cmd : public ps3av_cmd { u16 get_size(vuart_av_thread& /*vuart*/, const void* /*pkt_buf*/) override @@ -97,18 +1495,19 @@ struct generic_reply_cmd : public ps3av_cmd return 0; } - bool execute(vuart_av_thread &vuart, const void *pkt_buf, u32 reply_max_size) override + void execute(vuart_av_thread &vuart, const void *pkt_buf) override { - auto pkt = static_cast(pkt_buf); + const auto pkt = static_cast(pkt_buf); - if (reply_max_size < sizeof(ps3av_pkt_reply_hdr)) + if (vuart.get_reply_buf_free_size() < sizeof(ps3av_pkt_reply_hdr)) { vuart.write_resp(pkt->cid, PS3AV_STATUS_BUFFER_OVERFLOW); - return false; + return; } + sys_uart.todo("Unimplemented cid=0x%08x", pkt->cid); + vuart.write_resp(pkt->cid, PS3AV_STATUS_SUCCESS); - return true; } }; @@ -137,7 +1536,7 @@ error_code sys_uart_receive(ppu_thread &ppu, vm::ptr buffer, u64 size, u32 return CELL_OK; } - if ((mode & ~1UL) != 0) + if (mode & ~(BLOCKING_BIG_OP | NOT_BLOCKING_BIG_OP)) { return CELL_EINVAL; } @@ -160,7 +1559,7 @@ error_code sys_uart_receive(ppu_thread &ppu, vm::ptr buffer, u64 size, u32 auto vuart_read = [&](u8 *buf, u32 buf_size) -> s32 { - const u32 ITER_SIZE = 4096; + constexpr u32 ITER_SIZE = 4096; std::unique_lock lock(vuart_thread.rx_mutex, std::defer_lock); if (!lock.try_lock()) @@ -241,7 +1640,7 @@ error_code sys_uart_send(ppu_thread &ppu, vm::cptr buffer, u64 size, u32 m return CELL_OK; } - if ((mode & ~3ul) != 0) + if (mode & ~(BLOCKING_BIG_OP | NOT_BLOCKING_OP | NOT_BLOCKING_BIG_OP)) { return CELL_EINVAL; } @@ -269,7 +1668,7 @@ error_code sys_uart_send(ppu_thread &ppu, vm::cptr buffer, u64 size, u32 m std::unique_lock lock(vuart_thread.tx_mutex, std::defer_lock); - const u32 ITER_SIZE = 4096; + constexpr u32 ITER_SIZE = 4096; if (mode & BLOCKING_BIG_OP) { @@ -397,20 +1796,59 @@ void vuart_av_thread::operator()() { while (thread_ctrl::state() != thread_state::aborting) { + if (Emu.IsPaused()) + { + thread_ctrl::wait_for(5000); + continue; + } + + const u64 hdmi_event_dist[2] = { hdmi_event_handler[0].time_until_next(), hdmi_event_handler[1].time_until_next() }; + bool update_dist = false; + + if (hdmi_event_dist[0] == 0) + { + dispatch_hdmi_event(hdmi_event_handler[0].get_occured_event(), UartAudioAvport::HDMI_0); + update_dist |= hdmi_event_handler[0].events_available(); + } + + if (hdmi_event_dist[1] == 0) + { + dispatch_hdmi_event(hdmi_event_handler[1].get_occured_event(), UartAudioAvport::HDMI_1); + update_dist |= hdmi_event_handler[1].events_available(); + } + + if (update_dist) + { + continue; + } + + const u64 wait_time = [&]() + { + if (hdmi_event_dist[0] != 0 && hdmi_event_dist[1] != 0) + return std::min(hdmi_event_dist[0], hdmi_event_dist[1]); + else + return std::max(hdmi_event_dist[0], hdmi_event_dist[1]); + }(); + std::unique_lock lock(tx_wake_m); if (!tx_buf.get_used_size()) { - tx_wake_c.wait_unlock(-1, lock); + tx_wake_c.wait_unlock(wait_time ? wait_time : -1, lock); } else { lock.unlock(); } - if (u32 read_size = read_tx_data(temp_tx_buf, sizeof(temp_tx_buf))) + if (u32 read_size = read_tx_data(temp_tx_buf, PS3AV_TX_BUF_SIZE)) { parse_tx_buffer(read_size); - commit_rx_buf(); + + // Give vsh some time + thread_ctrl::wait_for(1000 * 100 / g_cfg.core.clocks_scale); + + commit_rx_buf(false); + commit_rx_buf(true); } } } @@ -419,7 +1857,7 @@ void vuart_av_thread::parse_tx_buffer(u32 buf_size) { if (buf_size >= PS3AV_TX_BUF_SIZE) { - while (read_tx_data(temp_tx_buf, sizeof(temp_tx_buf)) >= PS3AV_TX_BUF_SIZE); + while (read_tx_data(temp_tx_buf, PS3AV_TX_BUF_SIZE) >= PS3AV_TX_BUF_SIZE); write_resp(reinterpret_cast*>(temp_tx_buf)[3], PS3AV_STATUS_BUFFER_OVERFLOW); return; } @@ -441,7 +1879,7 @@ void vuart_av_thread::parse_tx_buffer(u32 buf_size) { if (hdr->version >= 0x100 && hdr->version < PS3AV_VERSION) { - sys_uart.error("Unimplemented AV version: %x", hdr->version); + sys_uart.todo("Unimplemented AV version: 0x%04x", hdr->version); } write_resp(static_cast(hdr->cid.get()), PS3AV_STATUS_INVALID_COMMAND); @@ -456,7 +1894,7 @@ void vuart_av_thread::parse_tx_buffer(u32 buf_size) if (!cmd.get()) { - sys_uart.error("Unknown AV cmd: 0x%x", hdr->cid); + sys_uart.error("Unknown AV cmd: 0x%08x", hdr->cid); continue; } @@ -464,17 +1902,13 @@ void vuart_av_thread::parse_tx_buffer(u32 buf_size) if (cmd_size != pkt_size && cmd_size) { + sys_uart.error("Invalid size for cid=0x%x, expected=0x%x, got=0x%x", static_cast(pkt_storage)->cid, cmd_size, pkt_size); write_resp(static_cast(hdr->cid.get()), PS3AV_STATUS_INVALID_SAMPLE_SIZE); return; } - if (!cmd->execute(*this, pkt_storage, sizeof(temp_rx_buf) - temp_rx_buf_size)) - { - return; - } + cmd->execute(*this, pkt_storage); } - - // TODO: handle HDMI events } vuart_av_thread &vuart_av_thread::operator=(thread_state) @@ -518,22 +1952,35 @@ u32 vuart_av_thread::read_tx_data(void *data, u32 data_sz) return 0; } -void vuart_av_thread::write_resp(u32 cid, u32 status, const void *data, u32 data_size) +u32 vuart_av_thread::get_reply_buf_free_size() { - ps3av_pkt_reply_hdr pkt_hdr; + return sizeof(temp_rx_buf.buf) - temp_rx_buf.crnt_size; +} - pkt_hdr.version = PS3AV_VERSION; - pkt_hdr.status = status; - pkt_hdr.length = data_size + 8; - pkt_hdr.cid = cid | PS3AV_REPLY_BIT; +template +void vuart_av_thread::write_resp(u32 cid, u32 status, const void *data, u16 data_size) +{ + const ps3av_pkt_reply_hdr pkt_hdr = + { + PS3AV_VERSION, + data_size + 8U, + cid | PS3AV_REPLY_BIT, + status + }; + if (status != PS3AV_STATUS_SUCCESS) + { + sys_uart.error("Packet failed cid=0x%08x status=0x%02x", cid, status); + } + + temp_buf &buf = UseScBuffer ? temp_rx_sc_buf : temp_rx_buf; const u32 total_size = sizeof(pkt_hdr) + data_size; - if (temp_rx_buf_size + total_size <= PS3AV_RX_BUF_SIZE) + if (buf.crnt_size + total_size <= sizeof(buf.buf)) { - memcpy(&temp_rx_buf[temp_rx_buf_size], &pkt_hdr, sizeof(pkt_hdr)); - memcpy(&temp_rx_buf[temp_rx_buf_size + sizeof(pkt_hdr)], data, data_size); - temp_rx_buf_size += total_size; + memcpy(&buf.buf[buf.crnt_size], &pkt_hdr, sizeof(pkt_hdr)); + memcpy(&buf.buf[buf.crnt_size + sizeof(pkt_hdr)], data, data_size); + buf.crnt_size += total_size; } } @@ -541,44 +1988,62 @@ std::shared_ptr vuart_av_thread::get_cmd(u32 cid) { switch (cid) { - case PS3AV_CID_VIDEO_INIT: - case PS3AV_CID_AUDIO_INIT: - case PS3AV_CID_AV_GET_KSV_LIST_SIZE: - case PS3AV_CID_VIDEO_FORMAT: - case PS3AV_CID_VIDEO_PITCH: - case PS3AV_CID_VIDEO_ROUTE: - case PS3AV_CID_AV_VIDEO_DISABLE_SIG: - case PS3AV_CID_AV_TV_MUTE: - case PS3AV_CID_AV_UNK: - case PS3AV_CID_AV_UNK2: - case PS3AV_CID_VIDEO_GET_HW_CONF: - case PS3AV_CID_AV_HDMI_MODE: - case PS3AV_CID_AV_SET_ACP_PACKET: - case PS3AV_CID_AV_VIDEO_UNK4: - case PS3AV_CID_AV_ENABLE_EVENT: - case PS3AV_CID_AV_AUDIO_MUTE: - case PS3AV_CID_AUDIO_MUTE: - case PS3AV_CID_AUDIO_MODE: - case PS3AV_CID_AUDIO_CTRL: - case PS3AV_CID_AUDIO_ACTIVE: - case PS3AV_CID_AUDIO_INACTIVE: - case PS3AV_CID_AUDIO_SPDIF_BIT: - case PS3AV_CID_AVB_PARAM: - case PS3AV_CID_AV_INIT: - case 0xA0002: + case PS3AV_CID_AV_CEC_MESSAGE: + case PS3AV_CID_AV_UNK11: + case PS3AV_CID_AV_UNK12: return std::make_shared(); - case PS3AV_CID_AV_GET_HW_CONF: return std::make_shared(); - case PS3AV_CID_AV_GET_MONITOR_INFO: return std::make_shared(); + // AV commands + case PS3AV_CID_AV_INIT: return std::make_shared(); + case PS3AV_CID_AV_FIN: return std::make_shared(); + case PS3AV_CID_AV_GET_HW_CONF: return std::make_shared(); + case PS3AV_CID_AV_GET_MONITOR_INFO: return std::make_shared(); + case PS3AV_CID_AV_GET_BKSV_LIST: return std::make_shared(); + case PS3AV_CID_AV_ENABLE_EVENT: return std::make_shared(); + case PS3AV_CID_AV_DISABLE_EVENT: return std::make_shared(); + case PS3AV_CID_AV_TV_MUTE: return std::make_shared(); + case PS3AV_CID_AV_NULL_CMD: return std::make_shared(); + case PS3AV_CID_AV_GET_AKSV: return std::make_shared(); + case PS3AV_CID_AV_VIDEO_DISABLE_SIG: return std::make_shared(); + case PS3AV_CID_AV_VIDEO_YTRAPCONTROL: return std::make_shared(); + case PS3AV_CID_AV_AUDIO_MUTE: return std::make_shared(); + case PS3AV_CID_AV_ACP_CTRL: return std::make_shared(); + case PS3AV_CID_AV_SET_ACP_PACKET: return std::make_shared(); + case PS3AV_CID_AV_ADD_SIGNAL_CTL: return std::make_shared(); + case PS3AV_CID_AV_SET_CGMS_WSS: return std::make_shared(); + case PS3AV_CID_AV_HDMI_MODE: return std::make_shared(); + case PS3AV_CID_AV_GET_CEC_CONFIG: return std::make_shared(); + + // Video commands + case PS3AV_CID_VIDEO_INIT: return std::make_shared(); + case PS3AV_CID_VIDEO_ROUTE: return std::make_shared(); + case PS3AV_CID_VIDEO_FORMAT: return std::make_shared(); + case PS3AV_CID_VIDEO_PITCH: return std::make_shared(); + case PS3AV_CID_VIDEO_GET_HW_CONF: return std::make_shared(); + + // Audio commands + case PS3AV_CID_AUDIO_INIT: return std::make_shared(); + case PS3AV_CID_AUDIO_MODE: return std::make_shared(); + case PS3AV_CID_AUDIO_MUTE: return std::make_shared(); + case PS3AV_CID_AUDIO_ACTIVE: return std::make_shared(); + case PS3AV_CID_AUDIO_INACTIVE: return std::make_shared(); + case PS3AV_CID_AUDIO_SPDIF_BIT: return std::make_shared(); + case PS3AV_CID_AUDIO_CTRL: return std::make_shared(); + + // Multipacket + case PS3AV_CID_AVB_PARAM: return std::make_shared(); + default: return {}; } } -void vuart_av_thread::commit_rx_buf() +void vuart_av_thread::commit_rx_buf(bool syscon_buf) { + temp_buf &buf = syscon_buf ? temp_rx_sc_buf : temp_rx_buf; + std::unique_lock lock(rx_wake_m); - rx_buf.push(temp_rx_buf, temp_rx_buf_size); - temp_rx_buf_size = 0; + rx_buf.push(buf.buf, buf.crnt_size); + buf.crnt_size = 0; if (rx_buf.get_used_size()) { @@ -586,3 +2051,269 @@ void vuart_av_thread::commit_rx_buf() rx_wake_c.notify_all(); } } + +void vuart_av_thread::add_hdmi_events(UartHdmiEvent first_event, UartHdmiEvent last_event, bool hdmi_0, bool hdmi_1) +{ + if (hdmi_0) + { + hdmi_event_handler[0].set_target_state(first_event, last_event); + } + + if (hdmi_1 && g_cfg.core.debug_console_mode) + { + hdmi_event_handler[1].set_target_state(first_event, last_event); + } +} + +void vuart_av_thread::add_hdmi_events(UartHdmiEvent last_event, bool hdmi_0, bool hdmi_1) +{ + add_hdmi_events(last_event, last_event, hdmi_0, hdmi_1); +} + +void vuart_av_thread::dispatch_hdmi_event(UartHdmiEvent event, UartAudioAvport hdmi) +{ + const bool hdmi_0 = hdmi == UartAudioAvport::HDMI_0; + const bool hdmi_1 = hdmi == UartAudioAvport::HDMI_1; + + switch (event) + { + case UartHdmiEvent::UNPLUGGED: + { + add_unplug_event(hdmi_0, hdmi_1); + break; + } + case UartHdmiEvent::PLUGGED: + { + add_plug_event(hdmi_0, hdmi_1); + break; + } + case UartHdmiEvent::HDCP_DONE: + { + add_hdcp_done_event(hdmi_0, hdmi_1); + break; + } + default: break; + } +} + +RsxaudioAvportIdx vuart_av_thread::avport_to_idx(UartAudioAvport avport) +{ + switch (avport) + { + case UartAudioAvport::HDMI_0: + return RsxaudioAvportIdx::HDMI_0; + case UartAudioAvport::HDMI_1: + return RsxaudioAvportIdx::HDMI_1; + case UartAudioAvport::AVMULTI_0: + return RsxaudioAvportIdx::AVMULTI; + case UartAudioAvport::SPDIF_0: + return RsxaudioAvportIdx::SPDIF_0; + case UartAudioAvport::SPDIF_1: + return RsxaudioAvportIdx::SPDIF_1; + default: + ensure(false); + return RsxaudioAvportIdx::HDMI_0; + } +} + +void vuart_av_thread::add_unplug_event(bool hdmi_0, bool hdmi_1) +{ + if ((hdmi_events_bitmask & PS3AV_EVENT_BIT_UNPLUGGED) == 0) return; + + ps3av_header pkt{}; + pkt.version = av_cmd_ver; + pkt.length = sizeof(ps3av_header) - 4; + pkt.cid = PS3AV_CID_EVENT_UNPLUGGED; + + if (hdmi_0) + { + // TBA + hdcp_first_auth[0] = true; + commit_event_data(&pkt, sizeof(pkt)); + } + + if (hdmi_1) + { + // TBA + hdcp_first_auth[1] = true; + pkt.cid |= 0x10000; + commit_event_data(&pkt, sizeof(pkt)); + } +} + +void vuart_av_thread::add_plug_event(bool hdmi_0, bool hdmi_1) +{ + if ((hdmi_events_bitmask & PS3AV_EVENT_BIT_PLUGGED) == 0) return; + + ps3av_pkt_hdmi_plugged_event pkt{}; + pkt.hdr.version = av_cmd_ver; + pkt.hdr.length = sizeof(ps3av_pkt_hdmi_plugged_event) - 8; + pkt.hdr.cid = PS3AV_CID_EVENT_PLUGGED; + + if (hdmi_0) + { + // TBA + av_get_monitor_info_cmd::set_hdmi_display_cfg(*this, pkt.minfo, static_cast(UartAudioAvport::HDMI_0)); + commit_event_data(&pkt, sizeof(pkt) - 4); + } + + if (hdmi_1) + { + // TBA + memset(&pkt.minfo, 0, sizeof(pkt.minfo)); + pkt.hdr.cid |= 0x10000; + av_get_monitor_info_cmd::set_hdmi_display_cfg(*this, pkt.minfo, static_cast(UartAudioAvport::HDMI_1)); + commit_event_data(&pkt, sizeof(pkt) - 4); + } +} + +void vuart_av_thread::add_hdcp_done_event(bool hdmi_0, bool hdmi_1) +{ + u16 pkt_size = offsetof(ps3av_pkt_hdmi_hdcp_done_event, ksv_arr); + ps3av_pkt_hdmi_hdcp_done_event pkt{}; + pkt.hdr.version = av_cmd_ver; + + if (hdmi_behavior_mode == PS3AV_HDMI_BEHAVIOR_NORMAL || !(hdmi_behavior_mode & PS3AV_HDMI_BEHAVIOR_HDCP_OFF)) + { + pkt.ksv_cnt = 1; + memcpy(&pkt.ksv_arr[0], PS3AV_BKSV_VALUE, sizeof(PS3AV_BKSV_VALUE)); + pkt_size = (pkt_size + 5 * pkt.ksv_cnt + 3) & 0xFFFC; + } + + pkt.hdr.length = pkt_size - 4; + + if (hdmi_0) + { + // TBA + + if (hdcp_first_auth[0]) + { + if (hdmi_events_bitmask & PS3AV_EVENT_BIT_HDCP_DONE) + { + hdcp_first_auth[0] = false; + pkt.hdr.cid = PS3AV_CID_EVENT_HDCP_DONE; + commit_event_data(&pkt, pkt_size); + } + } + else if (hdmi_events_bitmask & PS3AV_EVENT_BIT_HDCP_REAUTH) + { + pkt.hdr.cid = PS3AV_CID_EVENT_HDCP_REAUTH; + commit_event_data(&pkt, pkt_size); + } + } + + if (hdmi_1) + { + // TBA + + if (hdcp_first_auth[1]) + { + if (hdmi_events_bitmask & PS3AV_EVENT_BIT_HDCP_DONE) + { + hdcp_first_auth[1] = false; + pkt.hdr.cid = PS3AV_CID_EVENT_HDCP_DONE | 0x10000; + commit_event_data(&pkt, pkt_size); + } + } + else if (hdmi_events_bitmask & PS3AV_EVENT_BIT_HDCP_REAUTH) + { + pkt.hdr.cid = PS3AV_CID_EVENT_HDCP_REAUTH | 0x10000; + commit_event_data(&pkt, pkt_size); + } + } +} + +void vuart_av_thread::commit_event_data(const void *data, u16 data_size) +{ + std::unique_lock lock(rx_wake_m); + rx_buf.push(data, data_size); + + if (rx_buf.get_used_size()) + { + lock.unlock(); + rx_wake_c.notify_all(); + } +} + +vuart_hdmi_event_handler::vuart_hdmi_event_handler(u64 time_offset) : time_offset(time_offset) +{ +} + +void vuart_hdmi_event_handler::set_target_state(UartHdmiEvent start_state, UartHdmiEvent end_state) +{ + ensure(start_state != UartHdmiEvent::NONE && static_cast(start_state) <= static_cast(end_state)); + + base_state = static_cast(std::min(static_cast(start_state) - 1, static_cast(current_to_state))); + target_state = end_state; + + if (!events_available()) + { + advance_state(); + } +} + +bool vuart_hdmi_event_handler::events_available() +{ + return time_of_next_event != 0; +} + +u64 vuart_hdmi_event_handler::time_until_next() +{ + const u64 current_time = get_system_time(); + + if (!events_available() || current_time + EVENT_TIME_THRESHOLD >= time_of_next_event) + { + return 0; + } + + return time_of_next_event - current_time; +} + +UartHdmiEvent vuart_hdmi_event_handler::get_occured_event() +{ + if (events_available() && time_until_next() == 0) + { + const UartHdmiEvent occured = current_to_state; + advance_state(); + + return occured; + } + + return UartHdmiEvent::NONE; +} + +void vuart_hdmi_event_handler::schedule_next() +{ + time_of_next_event = get_system_time() + (EVENT_TIME_DURATION + time_offset) * 100 / g_cfg.core.clocks_scale; +} + +void vuart_hdmi_event_handler::advance_state() +{ + current_state = current_to_state; + + while (base_state != target_state) + { + base_state = static_cast(static_cast(base_state) + 1); + + if (current_state == UartHdmiEvent::UNPLUGGED && base_state == UartHdmiEvent::UNPLUGGED) + { + continue; + } + + if (current_state == UartHdmiEvent::PLUGGED && base_state == UartHdmiEvent::PLUGGED) + { + continue; + } + + if (current_state == UartHdmiEvent::HDCP_DONE && base_state == UartHdmiEvent::PLUGGED) + { + continue; + } + + current_to_state = base_state; + schedule_next(); + return; + } + + time_of_next_event = 0; +} diff --git a/rpcs3/Emu/Cell/lv2/sys_uart.h b/rpcs3/Emu/Cell/lv2/sys_uart.h index 94519cff26..3618917b5c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_uart.h +++ b/rpcs3/Emu/Cell/lv2/sys_uart.h @@ -16,23 +16,40 @@ enum : u32 PS3AV_CID_AV_FIN = 0x00000002, PS3AV_CID_AV_GET_HW_CONF = 0x00000003, PS3AV_CID_AV_GET_MONITOR_INFO = 0x00000004, - PS3AV_CID_AV_GET_KSV_LIST_SIZE = 0x00000005, + PS3AV_CID_AV_GET_BKSV_LIST = 0x00000005, PS3AV_CID_AV_ENABLE_EVENT = 0x00000006, PS3AV_CID_AV_DISABLE_EVENT = 0x00000007, - PS3AV_CID_AV_GET_ALL_EDID = 0x00000008, + PS3AV_CID_AV_GET_PORT_STATE = 0x00000009, PS3AV_CID_AV_TV_MUTE = 0x0000000A, + PS3AV_CID_AV_NULL_CMD = 0x0000000B, + PS3AV_CID_AV_GET_AKSV = 0x0000000C, + PS3AV_CID_AV_UNK4 = 0x0000000D, + PS3AV_CID_AV_UNK5 = 0x0000000E, - PS3AV_CID_AV_VIDEO_CS = 0x00010001, PS3AV_CID_AV_VIDEO_MUTE = 0x00010002, PS3AV_CID_AV_VIDEO_DISABLE_SIG = 0x00010003, - PS3AV_CID_AV_VIDEO_UNK4 = 0x00010004, - PS3AV_CID_AV_AUDIO_PARAM = 0x00020001, + PS3AV_CID_AV_VIDEO_YTRAPCONTROL = 0x00010004, + PS3AV_CID_AV_VIDEO_UNK5 = 0x00010005, + PS3AV_CID_AV_VIDEO_UNK6 = 0x00010006, PS3AV_CID_AV_AUDIO_MUTE = 0x00020002, PS3AV_CID_AV_ACP_CTRL = 0x00020003, PS3AV_CID_AV_SET_ACP_PACKET = 0x00020004, - PS3AV_CID_AV_UNK = 0x00030001, - PS3AV_CID_AV_UNK2 = 0x00030003, + PS3AV_CID_AV_ADD_SIGNAL_CTL = 0x00030001, + PS3AV_CID_AV_SET_CC_CODE = 0x00030002, + PS3AV_CID_AV_SET_CGMS_WSS = 0x00030003, + PS3AV_CID_AV_SET_MACROVISION = 0x00030004, + PS3AV_CID_AV_UNK7 = 0x00030005, + PS3AV_CID_AV_UNK8 = 0x00030006, + PS3AV_CID_AV_UNK9 = 0x00030007, PS3AV_CID_AV_HDMI_MODE = 0x00040001, + PS3AV_CID_AV_UNK15 = 0x00050001, + + PS3AV_CID_AV_CEC_MESSAGE = 0x000A0001, + PS3AV_CID_AV_GET_CEC_CONFIG = 0x000A0002, + PS3AV_CID_AV_UNK11 = 0x000A0003, + PS3AV_CID_AV_UNK12 = 0x000A0004, + PS3AV_CID_AV_UNK13 = 0x000A0005, + PS3AV_CID_AV_UNK14 = 0x000A0006, PS3AV_CID_VIDEO_INIT = 0x01000001, PS3AV_CID_VIDEO_MODE = 0x01000002, @@ -40,7 +57,11 @@ enum : u32 PS3AV_CID_VIDEO_FORMAT = 0x01000004, PS3AV_CID_VIDEO_PITCH = 0x01000005, PS3AV_CID_VIDEO_GET_HW_CONF = 0x01000006, - PS3AV_CID_VIDEO_REGVAL = 0x01000008, + PS3AV_CID_VIDEO_GET_REG = 0x01000008, + PS3AV_CID_VIDEO_UNK = 0x01000009, + PS3AV_CID_VIDEO_UNK1 = 0x0100000A, + PS3AV_CID_VIDEO_UNK2 = 0x0100000B, + PS3AV_CID_VIDEO_UNK3 = 0x0100000C, PS3AV_CID_AUDIO_INIT = 0x02000001, PS3AV_CID_AUDIO_MODE = 0x02000002, @@ -50,15 +71,15 @@ enum : u32 PS3AV_CID_AUDIO_SPDIF_BIT = 0x02000006, PS3AV_CID_AUDIO_CTRL = 0x02000007, + PS3AV_CID_AVB_PARAM = 0x04000001, + PS3AV_CID_EVENT_UNPLUGGED = 0x10000001, PS3AV_CID_EVENT_PLUGGED = 0x10000002, PS3AV_CID_EVENT_HDCP_DONE = 0x10000003, PS3AV_CID_EVENT_HDCP_FAIL = 0x10000004, - PS3AV_CID_EVENT_HDCP_AUTH = 0x10000005, + PS3AV_CID_EVENT_HDCP_REAUTH = 0x10000005, PS3AV_CID_EVENT_HDCP_ERROR = 0x10000006, - PS3AV_CID_AVB_PARAM = 0x04000001, - PS3AV_REPLY_BIT = 0x80000000, PS3AV_RESBIT_720x480P = 0x0003, /* 0x0001 | 0x0002 */ @@ -67,8 +88,52 @@ enum : u32 PS3AV_RESBIT_1920x1080I = 0x0008, PS3AV_RESBIT_1920x1080P = 0x4000, + PS3AV_MONITOR_TYPE_NONE = 0, PS3AV_MONITOR_TYPE_HDMI = 1, PS3AV_MONITOR_TYPE_DVI = 2, + PS3AV_MONITOR_TYPE_AVMULTI = 3, + + PS3AV_COLORIMETRY_xvYCC_601 = 1, + PS3AV_COLORIMETRY_xvYCC_709 = 2, + PS3AV_COLORIMETRY_MD0 = 1 << 4, + PS3AV_COLORIMETRY_MD1 = 1 << 5, + PS3AV_COLORIMETRY_MD2 = 1 << 6, + + PS3AV_CS_SUPPORTED = 1, + PS3AV_RGB_SELECTABLE_QAUNTIZATION_RANGE = 8, + PS3AV_12BIT_COLOR = 16, + + PS3AV_MON_INFO_AUDIO_BLK_MAX = 16, + + PS3AV_MON_INFO_AUDIO_TYPE_LPCM = 1, + PS3AV_MON_INFO_AUDIO_TYPE_AC3 = 2, + PS3AV_MON_INFO_AUDIO_TYPE_AAC = 6, + PS3AV_MON_INFO_AUDIO_TYPE_DTS = 7, + PS3AV_MON_INFO_AUDIO_TYPE_DDP = 10, + PS3AV_MON_INFO_AUDIO_TYPE_DTS_HD = 11, + PS3AV_MON_INFO_AUDIO_TYPE_DOLBY_THD = 12, + + PS3AV_HDMI_BEHAVIOR_HDCP_OFF = 0x01, + PS3AV_HDMI_BEHAVIOR_DVI = 0x40, + PS3AV_HDMI_BEHAVIOR_EDID_PASS = 0x80, + PS3AV_HDMI_BEHAVIOR_NORMAL = 0xFF, + + PS3AV_EVENT_BIT_UNPLUGGED = 0x01, + PS3AV_EVENT_BIT_PLUGGED = 0x02, + PS3AV_EVENT_BIT_HDCP_DONE = 0x04, + PS3AV_EVENT_BIT_HDCP_FAIL = 0x08, + PS3AV_EVENT_BIT_HDCP_REAUTH = 0x10, + PS3AV_EVENT_BIT_HDCP_TOPOLOGY = 0x20, + PS3AV_EVENT_BIT_UNK = 0x80000000, + + PS3AV_HEAD_A_HDMI = 0, + PS3AV_HEAD_B_ANALOG = 1, + + PS3AV_AUDIO_PORT_HDMI_0 = 1 << 0, + PS3AV_AUDIO_PORT_HDMI_1 = 1 << 1, + PS3AV_AUDIO_PORT_AVMULTI = 1 << 10, + PS3AV_AUDIO_PORT_SPDIF_0 = 1 << 20, + PS3AV_AUDIO_PORT_SPDIF_1 = 1 << 21, PS3AV_STATUS_SUCCESS = 0x00, PS3AV_STATUS_RECEIVE_VUART_ERROR = 0x01, @@ -90,8 +155,12 @@ enum : u32 PS3AV_STATUS_INVALID_AUDIO_PARAM = 0x11, PS3AV_STATUS_UNSUPPORTED_HDMI_MODE = 0x12, PS3AV_STATUS_NO_SYNC_HEAD = 0x13, + PS3AV_STATUS_UNK_0x14 = 0x14, }; +const u8 PS3AV_AKSV_VALUE[5] = { 0x00, 0x00, 0x0F, 0xFF, 0xFF }; +const u8 PS3AV_BKSV_VALUE[5] = { 0xFF, 0xFF, 0xF0, 0x00, 0x00 }; + enum PS3_AV_OP_MODE : u32 { // BIG operation modes could send more then 4096 bytes @@ -101,12 +170,99 @@ enum PS3_AV_OP_MODE : u32 NOT_BLOCKING_OP = 2, }; +enum class UartHdmiEvent : u8 +{ + NONE = 0, + UNPLUGGED = 1, + PLUGGED = 2, + HDCP_DONE = 3, +}; + +enum class UartAudioCtrlID : u32 +{ + DAC_RESET = 0, + DAC_DE_EMPHASIS = 1, + AVCLK = 2, +}; + +enum class UartAudioAvport : u8 +{ + HDMI_0 = 0x0, + HDMI_1 = 0x1, + AVMULTI_0 = 0x10, + AVMULTI_1 = 0x11, + SPDIF_0 = 0x20, + SPDIF_1 = 0x21, +}; + +enum class UartAudioSource : u32 +{ + SERIAL = 0, + SPDIF = 1, +}; + +enum class UartAudioFreq : u32 +{ + _32K = 1, + _44K = 2, + _48K = 3, + _88K = 4, + _96K = 5, + _176K = 6, + _192K = 7, +}; + +enum class UartAudioFormat : u32 +{ + PCM = 1, + BITSTREAM = 0xFF, +}; + +enum class UartAudioSampleSize : u32 +{ + _16BIT = 1, + _20BIT = 2, + _24BIT = 3, +}; + +class vuart_hdmi_event_handler +{ +public: + + vuart_hdmi_event_handler(u64 time_offset = 0); + + void set_target_state(UartHdmiEvent start_state, UartHdmiEvent end_state); + bool events_available(); + + u64 time_until_next(); + UartHdmiEvent get_occured_event(); + +private: + + static constexpr u64 EVENT_TIME_DURATION = 20000; + static constexpr u64 EVENT_TIME_THRESHOLD = 1000; + + u64 time_of_next_event = 0; + const u64 time_offset = 0; + + // Assume that syscon initialized hdmi to plugged state + UartHdmiEvent current_state = UartHdmiEvent::PLUGGED; + UartHdmiEvent current_to_state = UartHdmiEvent::PLUGGED; + + UartHdmiEvent base_state = UartHdmiEvent::NONE; + UartHdmiEvent target_state = UartHdmiEvent::NONE; + + void schedule_next(); + void advance_state(); +}; + class vuart_av_thread; struct ps3av_cmd { virtual u16 get_size(vuart_av_thread &vuart, const void *pkt_buf) = 0; - virtual bool execute(vuart_av_thread &vuart, const void *pkt_buf, u32 reply_max_size) = 0; + virtual void execute(vuart_av_thread &vuart, const void *pkt_buf) = 0; + virtual ~ps3av_cmd() {}; }; class vuart_av_thread @@ -125,6 +281,12 @@ public: shared_mutex rx_wake_m{}; cond_variable rx_wake_c{}; + bool head_b_initialized = false; + u8 hdmi_behavior_mode = PS3AV_HDMI_BEHAVIOR_NORMAL; + u16 av_cmd_ver = 0; + u32 hdmi_events_bitmask = 0; + bool hdmi_res_set[2]{ false, false }; + void operator()(); void parse_tx_buffer(u32 buf_size); vuart_av_thread &operator=(thread_state); @@ -132,21 +294,48 @@ public: u32 enque_tx_data(const void *data, u32 data_sz); u32 get_tx_bytes(); u32 read_rx_data(void *data, u32 data_sz); - void write_resp(u32 cid, u32 status, const void *data = nullptr, u32 data_size = 0); + + u32 get_reply_buf_free_size(); + + template + void write_resp(u32 cid, u32 status, const void *data = nullptr, u16 data_size = 0); + + void add_hdmi_events(UartHdmiEvent first_event, UartHdmiEvent last_event, bool hdmi_0, bool hdmi_1); + void add_hdmi_events(UartHdmiEvent last_event, bool hdmi_0, bool hdmi_1); + + static RsxaudioAvportIdx avport_to_idx(UartAudioAvport avport); static constexpr auto thread_name = "VUART AV Thread"sv; private: + struct temp_buf + { + u32 crnt_size = 0; + u8 buf[PS3AV_RX_BUF_SIZE]{}; + }; + simple_ringbuf tx_buf{PS3AV_TX_BUF_SIZE}; simple_ringbuf rx_buf{PS3AV_RX_BUF_SIZE}; - u8 temp_tx_buf[PS3AV_TX_BUF_SIZE]; - u8 temp_rx_buf[PS3AV_RX_BUF_SIZE]; - u32 temp_rx_buf_size = 0; + + // uart_mngr could sometimes read past the tx_buffer due to weird size checks in FW, + // but no further than size of largest packet + u8 temp_tx_buf[PS3AV_TX_BUF_SIZE * 2]{}; + temp_buf temp_rx_buf{}; + temp_buf temp_rx_sc_buf{}; + + vuart_hdmi_event_handler hdmi_event_handler[2]{ 0, 5000 }; + bool hdcp_first_auth[2]{ true, true }; u32 read_tx_data(void *data, u32 data_sz); std::shared_ptr get_cmd(u32 cid); - void commit_rx_buf(); + void commit_rx_buf(bool syscon_buf); + + void add_unplug_event(bool hdmi_0, bool hdmi_1); + void add_plug_event(bool hdmi_0, bool hdmi_1); + void add_hdcp_done_event(bool hdmi_0, bool hdmi_1); + void commit_event_data(const void *data, u16 data_size); + void dispatch_hdmi_event(UartHdmiEvent event, UartAudioAvport hdmi); }; using vuart_av = named_thread; @@ -157,6 +346,8 @@ struct vuart_params be_t tx_buf_size; }; +static_assert(sizeof(vuart_params) == 16); + struct ps3av_pkt_reply_hdr { be_t version; @@ -165,6 +356,8 @@ struct ps3av_pkt_reply_hdr be_t status; }; +static_assert(sizeof(ps3av_pkt_reply_hdr) == 12); + struct ps3av_header { be_t version; @@ -172,6 +365,8 @@ struct ps3av_header be_t cid; }; +static_assert(sizeof(ps3av_header) == 8); + struct ps3av_info_resolution { be_t res_bits; @@ -183,7 +378,7 @@ struct ps3av_info_cs u8 rgb; u8 yuv444; u8 yuv422; - u8 reserved; + u8 colorimetry_data; }; struct ps3av_info_color @@ -222,9 +417,22 @@ struct ps3av_get_monitor_info_reply u8 supported_ai; u8 speaker_info; be_t num_of_audio_block; - ps3av_info_audio audio_info[29]; + ps3av_info_audio audio_info[PS3AV_MON_INFO_AUDIO_BLK_MAX]; + be_t hor_screen_size; + be_t ver_screen_size; + u8 supported_content_types; + u8 reserved_1[3]; + ps3av_info_resolution res_60_packed_3D; + ps3av_info_resolution res_50_packed_3D; + ps3av_info_resolution res_other_3D; + ps3av_info_resolution res_60_sbs_3D; + ps3av_info_resolution res_50_sbs_3D; + u8 vendor_specific_flags; + u8 reserved_2[7]; }; +static_assert(sizeof(ps3av_get_monitor_info_reply) == 208); + struct ps3av_get_monitor_info { ps3av_header hdr; @@ -232,14 +440,321 @@ struct ps3av_get_monitor_info be_t reserved; }; +static_assert(sizeof(ps3av_get_monitor_info) == 12); + struct ps3av_get_hw_info_reply { be_t num_of_hdmi; be_t num_of_avmulti; be_t num_of_spdif; + be_t extra_bistream_support; +}; + +static_assert(sizeof(ps3av_get_hw_info_reply) == 8); + +struct ps3av_pkt_set_hdmi_mode +{ + ps3av_header hdr; + u8 mode; + u8 resv[3]; +}; + +static_assert(sizeof(ps3av_pkt_set_hdmi_mode) == 12); + +struct ps3av_pkt_audio_mode +{ + ps3av_header hdr; + UartAudioAvport avport; + u8 reserved0[3]; + be_t mask; + be_t audio_num_of_ch; + be_t audio_fs; + be_t audio_word_bits; + be_t audio_format; + be_t audio_source; + u8 audio_enable[4]; + u8 audio_swap[4]; + u8 audio_map[4]; + be_t audio_layout; + be_t audio_downmix; + be_t audio_downmix_level; + u8 audio_cs_info[8]; +}; + +static_assert(sizeof(ps3av_pkt_audio_mode) == 68); + +struct ps3av_pkt_audio_mute +{ + ps3av_header hdr; + UartAudioAvport avport; + u8 reserved0[3]; + u8 mute; +}; + +static_assert(sizeof(ps3av_pkt_audio_mute) == 13); + +struct ps3av_pkt_audio_set_active +{ + ps3av_header hdr; + be_t audio_port; +}; + +static_assert(sizeof(ps3av_pkt_audio_set_active) == 12); + +struct ps3av_pkt_audio_spdif_bit +{ + ps3av_header hdr; + UartAudioAvport avport; + u8 reserved0[3]; + be_t audio_port; + be_t spdif_bit_data[12]; +}; + +static_assert(sizeof(ps3av_pkt_audio_spdif_bit) == 64); + +struct ps3av_pkt_audio_ctrl +{ + ps3av_header hdr; + be_t audio_ctrl_id; + be_t audio_ctrl_data[4]; +}; + +static_assert(sizeof(ps3av_pkt_audio_ctrl) == 28); + +struct ps3av_pkt_hdmi_plugged_event +{ + ps3av_header hdr; + ps3av_get_monitor_info_reply minfo; +}; + +static_assert(sizeof(ps3av_pkt_hdmi_plugged_event) == 216); + +struct ps3av_pkt_hdmi_hdcp_done_event +{ + ps3av_header hdr; + be_t ksv_cnt; + u8 ksv_arr[20][5]; +}; + +static_assert(sizeof(ps3av_pkt_hdmi_hdcp_done_event) == 112); + +struct ps3av_pkt_av_init +{ + ps3av_header hdr; + be_t event_bit; +}; + +static_assert(sizeof(ps3av_pkt_av_init) == 12); + +struct ps3av_pkt_av_init_reply +{ + be_t unk; +}; + +static_assert(sizeof(ps3av_pkt_av_init_reply) == 4); + +struct ps3av_pkt_enable_event +{ + ps3av_header hdr; + be_t event_bit; +}; + +static_assert(sizeof(ps3av_pkt_enable_event) == 12); + +struct ps3av_pkt_get_bksv +{ + ps3av_header hdr; + be_t avport; + u8 resv[2]; +}; + +static_assert(sizeof(ps3av_pkt_get_bksv) == 12); + +struct ps3av_pkt_get_bksv_reply +{ + be_t avport; + u8 resv[2]; + be_t ksv_cnt; + u8 ksv_arr[20][5]; +}; + +static_assert(sizeof(ps3av_pkt_get_bksv_reply) == 108); + +struct ps3av_pkt_video_get_hw_cfg_reply +{ + be_t gx_available; +}; + +static_assert(sizeof(ps3av_pkt_video_get_hw_cfg_reply) == 4); + +struct ps3av_pkt_video_set_pitch +{ + ps3av_header hdr; + be_t video_head; + be_t pitch; +}; + +static_assert(sizeof(ps3av_pkt_video_set_pitch) == 16); + +struct ps3av_pkt_get_aksv_reply +{ + be_t ksv_size; + u8 ksv_arr[2][5]; + u8 resv[2]; +}; + +static_assert(sizeof(ps3av_pkt_get_aksv_reply) == 16); + +struct ps3av_pkt_inc_avset +{ + ps3av_header hdr; + be_t num_of_video_pkt; + be_t num_of_audio_pkt; + be_t num_of_av_video_pkt; + be_t num_of_av_audio_pkt; +}; + +static_assert(sizeof(ps3av_pkt_inc_avset) == 16); + +struct ps3av_pkt_av_audio_param +{ + ps3av_header hdr; + be_t avport; + be_t resv; + u8 mclk; + u8 ns[3]; + u8 enable; + u8 swaplr; + u8 fifomap; + u8 inputctrl; + u8 inputlen; + u8 layout; + u8 info[5]; + u8 chstat[5]; +}; + +static_assert(sizeof(ps3av_pkt_av_audio_param) == 32); + +struct ps3av_pkt_av_video_cs +{ + ps3av_header hdr; + be_t avport; + be_t av_vid; + be_t av_cs_out; + be_t av_cs_in; + u8 dither; + u8 bitlen_out; + u8 super_white; + u8 aspect; + u8 unk1; + u8 unk2; + u8 resv[2]; +}; + +static_assert(sizeof(ps3av_pkt_av_video_cs) == 24); + +struct ps3av_pkt_video_mode +{ + ps3av_header hdr; + be_t video_head; + be_t unk1; + be_t unk2; + be_t video_vid; + be_t width; + be_t height; + be_t pitch; + be_t video_out_format; + be_t video_format; + be_t unk3; + be_t video_order; + be_t unk4; +}; + +static_assert(sizeof(ps3av_pkt_video_mode) == 48); + +struct ps3av_pkt_av_video_ytrapcontrol +{ + ps3av_header hdr; + be_t unk1; + be_t unk2; +}; + +static_assert(sizeof(ps3av_pkt_av_video_ytrapcontrol) == 12); + +struct ps3av_pkt_av_get_cec_config_reply +{ + be_t cec_present; +}; + +struct ps3av_pkt_video_format +{ + ps3av_header hdr; + be_t video_head; + be_t video_format; + be_t unk; + be_t video_order; +}; + +static_assert(sizeof(ps3av_pkt_video_format) == 20); + +struct ps3av_pkt_av_set_cgms_wss +{ + ps3av_header hdr; + be_t avport; + u8 resv[2]; + be_t cgms_wss; +}; + +static_assert(sizeof(ps3av_pkt_av_set_cgms_wss) == 16); + +struct ps3av_pkt_set_acp_packet +{ + ps3av_header hdr; + u8 avport; + u8 pkt_type; + u8 resv[2]; + u8 pkt_data[32]; +}; + +static_assert(sizeof(ps3av_pkt_set_acp_packet) == 44); + +struct ps3av_pkt_acp_ctrl +{ + ps3av_header hdr; + u8 avport; + u8 packetctl; + u8 resv[2]; +}; + +static_assert(sizeof(ps3av_pkt_acp_ctrl) == 12); + +struct ps3av_pkt_add_signal_ctl +{ + ps3av_header hdr; + be_t avport; + be_t signal_ctl; +}; + +static_assert(sizeof(ps3av_pkt_add_signal_ctl) == 12); + +struct ps3av_pkt_av_audio_mute +{ + ps3av_header hdr; + be_t avport; + be_t mute; +}; + +static_assert(sizeof(ps3av_pkt_av_audio_mute) == 12); + +struct ps3av_pkt_video_disable_sig +{ + ps3av_header hdr; + be_t avport; be_t resv; }; +static_assert(sizeof(ps3av_pkt_video_disable_sig) == 12); + // SysCalls error_code sys_uart_initialize(ppu_thread &ppu);