diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index d0bd68819fc8..d37236b00590 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -82,7 +82,7 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max) if (ret.ec != std::errc() || ret.ptr != end || (start[0] == '-' && sign < 0)) { - if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value); + if (out) cfg_log.error("cfg::try_to_int64('%s'): invalid integer", value); return false; } @@ -90,7 +90,7 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max) if (result < min || result > max) { - if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%d..%d)", value, min, max); + if (out) cfg_log.error("cfg::try_to_int64('%s'): out of bounds (%d..%d)", value, min, max); return false; } @@ -121,13 +121,13 @@ bool cfg::try_to_uint64(u64* out, const std::string& value, u64 min, u64 max) if (ret.ec != std::errc() || ret.ptr != end) { - if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value); + if (out) cfg_log.error("cfg::try_to_uint64('%s'): invalid integer", value); return false; } if (result < min || result > max) { - if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%u..%u)", value, min, max); + if (out) cfg_log.error("cfg::try_to_uint64('%s'): out of bounds (%u..%u)", value, min, max); return false; } diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index f071cf3f8c17..366ee81520e6 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -358,6 +358,7 @@ target_sources(rpcs3_emu PRIVATE Io/usb_device.cpp Io/Skylander.cpp Io/GHLtar.cpp + Io/Buzz.cpp ) # Np diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index e308a5aaf5d4..6edc751d5d03 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -15,6 +15,7 @@ #include "Emu/Io/usb_device.h" #include "Emu/Io/Skylander.h" #include "Emu/Io/GHLtar.h" +#include "Emu/Io/Buzz.h" #include @@ -144,6 +145,7 @@ usb_handler_thread::usb_handler_thread() bool found_skylander = false; bool found_ghltar = false; + bool found_buzz = false; for (ssize_t index = 0; index < ndev; index++) { @@ -197,10 +199,14 @@ usb_handler_thread::usb_handler_thread() check_device(0x044F, 0xB660, 0xB660, "Thrustmaster T500 RS Gear Shift"); // Buzz controllers - check_device(0x054C, 0x1000, 0x1040, "buzzer0"); - check_device(0x054C, 0x0001, 0x0041, "buzzer1"); - check_device(0x054C, 0x0042, 0x0042, "buzzer2"); - check_device(0x046D, 0xC220, 0xC220, "buzzer9"); + if (check_device(0x054C, 0x1000, 0x1040, "buzzer0")) + found_buzz = true; + if (check_device(0x054C, 0x0001, 0x0041, "buzzer1")) + found_buzz = true; + if (check_device(0x054C, 0x0042, 0x0042, "buzzer2")) + found_buzz = true; + if (check_device(0x046D, 0xC220, 0xC220, "buzzer9")) + found_buzz = true; // GCon3 Gun check_device(0x0B9A, 0x0800, 0x0800, "guncon3"); @@ -223,6 +229,15 @@ usb_handler_thread::usb_handler_thread() usb_devices.push_back(std::make_shared()); } + if (!found_buzz) + { + sys_usbd.notice("Adding emulated Buzz! buzzer"); + usb_devices.push_back(std::make_shared(0, 3)); + // The current buzz emulation piggybacks on the pad input. + // Since there can only be 7 pads connected on a PS3 the 8th player is currently not supported + usb_devices.push_back(std::make_shared(4, 6)); + } + for (u32 index = 0; index < MAX_SYS_USBD_TRANSFERS; index++) { transfers[index].transfer = libusb_alloc_transfer(8); diff --git a/rpcs3/Emu/Io/Buzz.cpp b/rpcs3/Emu/Io/Buzz.cpp new file mode 100644 index 000000000000..5ff807616789 --- /dev/null +++ b/rpcs3/Emu/Io/Buzz.cpp @@ -0,0 +1,104 @@ +// Buzz! buzzer emulator + +#include "stdafx.h" +#include "Buzz.h" +#include "Emu/Cell/lv2/sys_usbd.h" +#include "Input/pad_thread.h" + +LOG_CHANNEL(buzz_log); + +usb_device_buzz::usb_device_buzz(int first_controller, int last_controller) +{ + this->first_controller = first_controller; + this->last_controller = last_controller; + + device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0x00, 0x00, 0x00, 0x08, 0x054c, 0x0002, 0x05a1, 0x03, 0x01, 0x00, 0x01}); + auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x0022, 0x01, 0x01, 0x00, 0x80, 0x32})); + config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00})); + config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x33, 0x01, 0x22, 0x004e})); + config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0008, 0x0A})); +} + +usb_device_buzz::~usb_device_buzz() +{ +} + +void usb_device_buzz::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) +{ + transfer->fake = true; + + // Control transfers are nearly instant + switch (bmRequestType) + { + case 0x01: + case 0x21: + case 0x80: + buzz_log.error("Unhandled Query Len: 0x%02X", buf_size); + buzz_log.error("Unhandled Query Type: 0x%02X", (buf_size > 0) ? buf[0] : -1); + break; + default: + usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); + break; + } +} + +void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) +{ + transfer->fake = true; + transfer->expected_count = 5; + transfer->expected_result = HC_CC_NOERR; + // Interrupt transfers are slow (6ms, TODO accurate measurement) + transfer->expected_time = get_timestamp() + 6000; + + memset(buf, 0, buf_size); + + // https://gist.github.com/Lewiscowles1986/eef220dac6f0549e4702393a7b9351f6 + buf[0] = 0x7f; + buf[1] = 0x7f; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0xf0; + + const auto handler = pad::get_current_handler(); + const auto& pads = handler->GetPads(); + + for (int index = 0; index <= (last_controller - first_controller); index++) + { + const auto pad = pads[first_controller + index]; + + if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + continue; + + for (Button& button : pad->m_buttons) + { + if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) + { + switch (button.m_outKeyCode) + { + case CELL_PAD_CTRL_R1: + if (button.m_pressed) + buf[2 + (0 + 5 * index) / 8] |= 1 << ((0 + 5 * index) % 8); // Red + break; + case CELL_PAD_CTRL_TRIANGLE: + if (button.m_pressed) + buf[2 + (4 + 5 * index) / 8] |= 1 << ((4 + 5 * index) % 8); // Blue + break; + case CELL_PAD_CTRL_SQUARE: + if (button.m_pressed) + buf[2 + (3 + 5 * index) / 8] |= 1 << ((3 + 5 * index) % 8); // Orange + break; + case CELL_PAD_CTRL_CIRCLE: + if (button.m_pressed) + buf[2 + (2 + 5 * index) / 8] |= 1 << ((2 + 5 * index) % 8); // Green + break; + case CELL_PAD_CTRL_CROSS: + if (button.m_pressed) + buf[2 + (1 + 5 * index) / 8] |= 1 << ((1 + 5 * index) % 8); // Yellow + break; + default: + break; + } + } + } + } +} diff --git a/rpcs3/Emu/Io/Buzz.h b/rpcs3/Emu/Io/Buzz.h new file mode 100644 index 000000000000..ef9df8d4c058 --- /dev/null +++ b/rpcs3/Emu/Io/Buzz.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Emu/Io/usb_device.h" + +class usb_device_buzz : public usb_device_emulated +{ + int first_controller; + int last_controller; + +public: + usb_device_buzz(int first_controller, int last_controller); + ~usb_device_buzz(); + + void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override; + void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override; +}; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index ff0a3243a6f7..92b3c39f5c2a 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -76,6 +76,7 @@ true + @@ -445,6 +446,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 85234f20a700..2e3afc1bd392 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -896,6 +896,9 @@ Emu\Io + + Emu\Io + Emu\Cell\lv2 @@ -1807,6 +1810,9 @@ Emu\Io + + Emu\Io + Emu\NP