diff --git a/rpcs3/Emu/Io/usio.cpp b/rpcs3/Emu/Io/usio.cpp index 9b1cea3e635b..2942ef8e0bf4 100644 --- a/rpcs3/Emu/Io/usio.cpp +++ b/rpcs3/Emu/Io/usio.cpp @@ -3,9 +3,7 @@ #include "stdafx.h" #include "usio.h" -#include "Emu/Cell/lv2/sys_usbd.h" #include "Input/pad_thread.h" -#include "Emu/System.h" #include "Emu/IdManager.h" #include "Emu/system_utils.hpp" @@ -120,7 +118,7 @@ void usb_device_usio::load_backup() if (usio_backup_file.size() != file_size) { - usio_log.trace("Invalid USIO Backup file detected. Treating it as an empty file: %s", usio_backup_path); + usio_log.trace("Invalid USIO Backup file detected: %s", usio_backup_path); usio_backup_file.trunc(file_size); return; } @@ -130,8 +128,9 @@ void usb_device_usio::load_backup() void usb_device_usio::save_backup() { - if (!usio_backup_file) + if (!usio_backup_file && !usio_backup_path.empty() && !usio_backup_file.open(usio_backup_path, fs::create + fs::write + fs::lock)) { + usio_log.error("Failed to create a new USIO Backup file: %s", usio_backup_path); return; } @@ -144,7 +143,7 @@ void usb_device_usio::translate_input() std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - std::vector input_buf = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + std::vector input_buf = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; constexpr le_t c_small_hit = 0x4D0; constexpr le_t c_big_hit = 0x1800; le_t test_keys = 0x0000; @@ -263,23 +262,23 @@ void usb_device_usio::translate_input() std::memcpy(input_buf.data(), &test_keys, sizeof(u16)); std::memcpy(input_buf.data() + 16, &coin_counter, sizeof(u16)); - q_replies.push(input_buf); - q_replies.push({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); + response = std::move(input_buf); } -void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector& data) +void usb_device_usio::usio_write(u8 channel, u16 reg, std::vector& data) { - auto write_memory = [&](std::vector& memory, bool exact_size = true) + auto write_memory = [&](std::vector& memory) { - ensure(data.size() == memory.size() || (data.size() <= memory.size() && !exact_size)); - memcpy(memory.data(), data.data(), data.size()); + auto size = memory.size(); + memory = std::move(data); + memory.resize(size); }; const auto get_u16 = [&](std::string_view usio_func) -> u16 { if (data.size() != 2) { - usio_log.fatal("data.size() is %d, expected 2 for get_u16 in %s", data.size(), usio_func); + usio_log.error("data.size() is %d, expected 2 for get_u16 in %s", data.size(), usio_func); } return *reinterpret_cast*>(data.data()); }; @@ -290,19 +289,18 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector& dat { case 0x0002: { - usio_log.notice("SetSystemError: 0x%04X", get_u16("SetSystemError")); + usio_log.trace("SetSystemError: 0x%04X", get_u16("SetSystemError")); break; } case 0x000A: { - u16 command = get_u16("ClearSram"); - ensure(command == 0x6666, "USIO: Unexpected Command instead of ClearSram"); - usio_log.notice("ClearSram"); + if (get_u16("ClearSram") == 0x6666) + usio_log.trace("ClearSram"); break; } case 0x0028: { - usio_log.notice("SetExpansionMode: 0x%04X", get_u16("SetExpansionMode")); + usio_log.trace("SetExpansionMode: 0x%04X", get_u16("SetExpansionMode")); break; } case 0x0048: @@ -310,7 +308,7 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector& dat case 0x0068: case 0x0078: { - usio_log.notice("SetHopperRequest(Hopper: %d, Request: 0x%04X)", (reg - 0x48) / 0x10, get_u16("SetHopperRequest")); + usio_log.trace("SetHopperRequest(Hopper: %d, Request: 0x%04X)", (reg - 0x48) / 0x10, get_u16("SetHopperRequest")); break; } case 0x004A: @@ -318,7 +316,7 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector& dat case 0x006A: case 0x007A: { - usio_log.notice("SetHopperRequest(Hopper: %d, Limit: 0x%04X)", (reg - 0x4A) / 0x10, get_u16("SetHopperLimit")); + usio_log.trace("SetHopperRequest(Hopper: %d, Limit: 0x%04X)", (reg - 0x4A) / 0x10, get_u16("SetHopperLimit")); break; } default: @@ -337,7 +335,7 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector& dat { case 0x0000: { - write_memory(g_fxo->get().backup_memory, false); + write_memory(g_fxo->get().backup_memory); break; } case 0x0180: @@ -358,34 +356,6 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector& dat void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) { - auto push_zeroes = [&]() - { - // Give it 00s - std::vector zeroes; - u16 left = size; - while (left > 0) - { - u16 to_push = std::min(left, static_cast(64)); - zeroes.resize(to_push); - q_replies.push(zeroes); - left -= to_push; - } - }; - - auto push_vector = [&](std::vector& memory) - { - std::vector buffer; - u16 left = size; - while (left > 0) - { - u16 to_push = std::min(left, static_cast(64)); - buffer.resize(to_push); - memcpy(buffer.data(), memory.data() + (size - left), buffer.size()); - q_replies.push(buffer); - left -= to_push; - } - }; - if (channel == 0) { switch (reg) @@ -395,21 +365,19 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) // Get Buffer, rarely gives a reply on real HW // First U16 seems to be a timestamp of sort // Purpose seems related to connectivity check - q_replies.push({0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); + response = {0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; break; } case 0x0080: { // Card reader check - 1 - ensure(size == 0x10); - q_replies.push({0x02, 0x03, 0x06, 0x00, 0xFF, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00}); + response = {0x02, 0x03, 0x06, 0x00, 0xFF, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00}; break; } case 0x7000: { // Card reader check - 2 - ensure(size == 0x06); - // No data returned + response.resize(size); break; } case 0x1080: @@ -420,28 +388,22 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) } case 0x1800: { - usio_log.trace("Firmware Query on 0x1800"); - ensure(size == 0x70); // Firmware // "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG." - q_replies.push({0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); - q_replies.push({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); + response = {0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; break; } case 0x1880: { // Seems to contain a few extra bytes of info in addition to the firmware string - usio_log.trace("Firmware query on 0x1880"); - ensure(size == 0x70); // Firmware // "NBGI2;USIO01;Ver1.00;JPN,Multipurpose with PPG." - q_replies.push({0x4E, 0x42, 0x47, 0x49, 0x32, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); - q_replies.push({0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x08, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); + response = {0x4E, 0x42, 0x47, 0x49, 0x32, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x08, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; break; } default: { - usio_log.fatal("Unhandled channel 0 register read: 0x%04X", reg); + usio_log.error("Unhandled channel 0 register read: 0x%04X", reg); break; } } @@ -458,32 +420,30 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) { case 0x0000: { - ensure(size <= 0xB8); - push_vector(g_fxo->get().backup_memory); + response = g_fxo->get().backup_memory; break; } case 0x0180: { - ensure(size == 0x28); - push_vector(g_fxo->get().last_game_status); + response = g_fxo->get().last_game_status; break; } case 0x0200: { - ensure(size == 0x100); + //ensure(size == 0x100); // No data returned break; } case 0x1000: { - ensure(size == 0x1000); - push_zeroes(); + //ensure(size == 0x1000); + response.resize(size); break; } default: { - usio_log.fatal("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg); - push_zeroes(); + usio_log.error("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg); + response.resize(size); break; } } @@ -491,8 +451,8 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) } default: { - usio_log.fatal("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg); - push_zeroes(); + usio_log.error("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg); + response.resize(size); break; } } @@ -509,9 +469,11 @@ void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, Us { constexpr u8 USIO_COMMAND_WRITE = 0x90; constexpr u8 USIO_COMMAND_READ = 0x10; + constexpr u8 USIO_COMMAND_INIT = 0xA0; static bool expecting_data = false; static std::vector usio_data; + static u32 response_seek = 0; static u8 usio_channel = 0; static u16 usio_register = 0; static u16 usio_length = 0; @@ -521,11 +483,6 @@ void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, Us // The latency varies per operation but it doesn't seem to matter for this device so let's go fast! transfer->expected_time = get_timestamp(); - if (!usio_backup_path.empty() && !usio_backup_file && !usio_backup_file.open(usio_backup_path, fs::create + fs::read + fs::write + fs::lock)) - { - usio_log.error("Failed to create a new USIO Backup file: %s", usio_backup_path); - } - switch (endpoint) { case 0x01: @@ -556,56 +513,38 @@ void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, Us { usio_log.trace("UsioWrite(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length); ensure(((~(usio_register >> 8)) & 0xF0) == buf[1]); - expecting_data = true; usio_data.clear(); - return; } - - if ((buf[0] & USIO_COMMAND_READ) == USIO_COMMAND_READ) + else if ((buf[0] & USIO_COMMAND_READ) == USIO_COMMAND_READ) { usio_log.trace("UsioRead(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length); + response_seek = 0; + response.clear(); usio_read(usio_channel, usio_register, usio_length); - return; } - - // Init and reset commands - if ((buf[0] & 0xA0) == 0xA0) + else if ((buf[0] & USIO_COMMAND_INIT) == USIO_COMMAND_INIT) // Init and reset commands { - const std::array init_command = {0xA0, 0xF0}; // This kind of command starts with 0xA0, 0xF0 commonly. For example, {0xA0, 0xF0, 0x28, 0x00, 0x00, 0x80} - ensure(memcmp(buf, init_command.data(), 2) == 0); - return; + //const std::array init_command = {0xA0, 0xF0}; // This kind of command starts with 0xA0, 0xF0 commonly. For example, {0xA0, 0xF0, 0x28, 0x00, 0x00, 0x80} + //ensure(memcmp(buf, init_command.data(), 2) == 0); } - - fmt::throw_exception("Received an unexpected command: 0x%02X", buf[0]); + else + { + usio_log.error("Received an unexpected command: 0x%02X", buf[0]); + } + break; } case 0x82: { // Read endpoint - if (!q_replies.empty()) - { - // Sometimes software will outright ignore what usio sends and read with a buffer of 0 - if (buf_size == 0) - { - transfer->expected_count = q_replies.front().size(); - q_replies.pop(); - break; - } - - // Otherwise we expect the buffer to be appropriately sized - ensure(buf_size >= q_replies.front().size()); - memcpy(buf, q_replies.front().data(), q_replies.front().size()); - transfer->expected_count = q_replies.front().size(); - q_replies.pop(); - } - else - { - transfer->expected_count = 0; - } + const u32 size = std::min(buf_size, static_cast(response.size() - response_seek)); + memcpy(buf, response.data() + response_seek, size); + response_seek += size; + transfer->expected_count = size; break; } default: - usio_log.fatal("Unhandled endpoint: 0x%x", endpoint); + usio_log.error("Unhandled endpoint: 0x%x", endpoint); break; } } diff --git a/rpcs3/Emu/Io/usio.h b/rpcs3/Emu/Io/usio.h index a6e6b9e6600e..28a34ea9e091 100644 --- a/rpcs3/Emu/Io/usio.h +++ b/rpcs3/Emu/Io/usio.h @@ -1,7 +1,6 @@ #pragma once #include "Emu/Io/usb_device.h" -#include class usb_device_usio : public usb_device_emulated { @@ -17,7 +16,7 @@ class usb_device_usio : public usb_device_emulated void load_backup(); void save_backup(); void translate_input(); - void usio_write(u8 channel, u16 reg, const std::vector& data); + void usio_write(u8 channel, u16 reg, std::vector& data); void usio_read(u8 channel, u16 reg, u16 size); private: @@ -27,5 +26,5 @@ class usb_device_usio : public usb_device_emulated le_t coin_counter = 0; std::string usio_backup_path; fs::file usio_backup_file; - std::queue> q_replies; + std::vector response; };