diff --git a/pcsx2-qt/Settings/ControllerBindingWidget.cpp b/pcsx2-qt/Settings/ControllerBindingWidget.cpp
index 1c13e11015945..a1be4020f088e 100644
--- a/pcsx2-qt/Settings/ControllerBindingWidget.cpp
+++ b/pcsx2-qt/Settings/ControllerBindingWidget.cpp
@@ -23,6 +23,7 @@
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
+#include "ui_USBBindingWidget_Buzz.h"
#include "ui_USBBindingWidget_DrivingForce.h"
#include "ui_USBBindingWidget_Gametrak.h"
#include "ui_USBBindingWidget_GTForce.h"
@@ -1333,6 +1334,11 @@ USBBindingWidget* USBBindingWidget::createInstance(
has_template = true;
}
}
+ else if (type == "BuzzDevice")
+ {
+ Ui::USBBindingWidget_Buzz().setupUi(widget);
+ has_template = true;
+ }
else if (type == "Gametrak")
{
Ui::USBBindingWidget_Gametrak().setupUi(widget);
diff --git a/pcsx2-qt/Settings/USBBindingWidget_Buzz.ui b/pcsx2-qt/Settings/USBBindingWidget_Buzz.ui
new file mode 100644
index 0000000000000..e8e53dbecc3c2
--- /dev/null
+++ b/pcsx2-qt/Settings/USBBindingWidget_Buzz.ui
@@ -0,0 +1,918 @@
+
+
+ USBBindingWidget_Buzz
+
+
+
+ 0
+ 0
+ 1100
+ 500
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+ Player 1
+
+
+
-
+
+
+ Red
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Blue
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Orange
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Green
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Yellow
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Player 2
+
+
+
-
+
+
+ Red
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Blue
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Orange
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Green
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Yellow
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Player 3
+
+
+
-
+
+
+ Red
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Blue
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Orange
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Green
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Yellow
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Player 4
+
+
+
-
+
+
+ Red
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Blue
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Orange
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Green
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+ -
+
+
+ Yellow
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PushButton
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+
+
+
+
+ InputBindingWidget
+ QPushButton
+ Settings/InputBindingWidget.h
+
+
+
+
+
+
+
diff --git a/pcsx2-qt/pcsx2-qt.vcxproj b/pcsx2-qt/pcsx2-qt.vcxproj
index e8e3d4006c59c..0eeebb84b09a7 100644
--- a/pcsx2-qt/pcsx2-qt.vcxproj
+++ b/pcsx2-qt/pcsx2-qt.vcxproj
@@ -416,6 +416,9 @@
Document
+
+ Document
+
Document
diff --git a/pcsx2-qt/pcsx2-qt.vcxproj.filters b/pcsx2-qt/pcsx2-qt.vcxproj.filters
index 36eeae6e0283c..bd33d2fcce1b0 100644
--- a/pcsx2-qt/pcsx2-qt.vcxproj.filters
+++ b/pcsx2-qt/pcsx2-qt.vcxproj.filters
@@ -657,6 +657,9 @@
Settings
+
+ Settings
+
Settings
diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt
index 552efda4fc533..6177f31ed98cb 100644
--- a/pcsx2/CMakeLists.txt
+++ b/pcsx2/CMakeLists.txt
@@ -383,6 +383,7 @@ set(pcsx2USBSources
USB/usb-mic/usb-mic-singstar.cpp
USB/usb-msd/usb-msd.cpp
USB/usb-pad/lg/lg_ff.cpp
+ USB/usb-pad/usb-buzz.cpp
USB/usb-pad/usb-gametrak.cpp
USB/usb-pad/usb-realplay.cpp
USB/usb-pad/usb-pad-ff.cpp
@@ -420,6 +421,7 @@ set(pcsx2USBHeaders
USB/usb-mic/usb-mic-singstar.h
USB/usb-msd/usb-msd.h
USB/usb-pad/lg/lg_ff.h
+ USB/usb-pad/usb-buzz.h
USB/usb-pad/usb-gametrak.h
USB/usb-pad/usb-realplay.h
USB/usb-pad/usb-pad-sdl-ff.h
diff --git a/pcsx2/USB/deviceproxy.cpp b/pcsx2/USB/deviceproxy.cpp
index 78b26a5a3fae1..91890d5b899e6 100644
--- a/pcsx2/USB/deviceproxy.cpp
+++ b/pcsx2/USB/deviceproxy.cpp
@@ -3,6 +3,7 @@
#include "deviceproxy.h"
#include "usb-eyetoy/usb-eyetoy-webcam.h"
+#include "usb-pad/usb-buzz.h"
#include "usb-pad/usb-gametrak.h"
#include "usb-pad/usb-realplay.h"
#include "usb-hid/usb-hid.h"
diff --git a/pcsx2/USB/usb-pad/usb-buzz.cpp b/pcsx2/USB/usb-pad/usb-buzz.cpp
new file mode 100644
index 0000000000000..0b33da8c48ad6
--- /dev/null
+++ b/pcsx2/USB/usb-pad/usb-buzz.cpp
@@ -0,0 +1,327 @@
+// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
+// SPDX-License-Identifier: LGPL-3.0+
+
+#include "Host.h"
+#include "Input/InputManager.h"
+#include "StateWrapper.h"
+#include "USB/USB.h"
+#include "USB/deviceproxy.h"
+#include "USB/qemu-usb/USBinternal.h"
+#include "USB/qemu-usb/desc.h"
+#include "USB/usb-pad/usb-buzz.h"
+#include "USB/usb-pad/usb-pad.h"
+#include
+
+namespace usb_pad
+{
+ static const USBDescStrings desc_strings = {
+ "",
+ "Logitech Buzz(tm) Controller V1",
+ "",
+ "Logitech"};
+
+ static uint8_t dev_descriptor[] = {
+ 0x12, // bLength
+ 0x01, // bDescriptorType (Device)
+ 0x00, 0x02, // bcdUSB 2.00
+ 0x00, // bDeviceClass (Use class information in the Interface Descriptors)
+ 0x00, // bDeviceSubClass
+ 0x00, // bDeviceProtocol
+ 0x08, // bMaxPacketSize0 8
+ 0x4C, 0x05, // idVendor 0x054C
+ 0x02, 0x00, // idProduct 0x0002
+ 0xA1, 0x05, // bcdDevice 11.01
+ 0x03, // iManufacturer (String Index)
+ 0x01, // iProduct (String Index)
+ 0x00, // iSerialNumber (String Index)
+ 0x01, // bNumConfigurations 1
+ };
+
+ static const uint8_t config_descriptor[] = {
+ 0x09, // bLength
+ 0x02, // bDescriptorType (Configuration)
+ 0x22, 0x00, // wTotalLength 34
+ 0x01, // bNumInterfaces 1
+ 0x01, // bConfigurationValue
+ 0x00, // iConfiguration (String Index)
+ 0x80, // bmAttributes
+ 0x32, // bMaxPower 100mA
+
+ 0x09, // bLength
+ 0x04, // bDescriptorType (Interface)
+ 0x00, // bInterfaceNumber 0
+ 0x00, // bAlternateSetting
+ 0x01, // bNumEndpoints 1
+ 0x03, // bInterfaceClass
+ 0x00, // bInterfaceSubClass
+ 0x00, // bInterfaceProtocol
+ 0x00, // iInterface (String Index)
+
+ 0x09, // bLength
+ 0x21, // bDescriptorType (HID)
+ 0x11, 0x01, // bcdHID 1.11
+ 0x33, // bCountryCode
+ 0x01, // bNumDescriptors
+ 0x22, // bDescriptorType[0] (HID)
+ 0x4E, 0x00, // wDescriptorLength[0] 78
+
+ 0x07, // bLength
+ 0x05, // bDescriptorType (Endpoint)
+ 0x81, // bEndpointAddress (IN/D2H)
+ 0x03, // bmAttributes (Interrupt)
+ 0x08, 0x00, // wMaxPacketSize 8
+ 0x0A, // bInterval 10 (unit depends on device speed)
+ };
+
+ static const uint8_t hid_report_descriptor[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x04, // Usage (Joystick)
+ 0xA1, 0x01, // Collection (Application)
+ 0xA1, 0x02, // Collection (Logical)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x02, // Report Count (2)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x46, 0xFF, 0x00, // Physical Maximum (255)
+ 0x09, 0x30, // Usage (X)
+ 0x09, 0x31, // Usage (Y)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x14, // Report Count (20)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x45, 0x01, // Physical Maximum (1)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x01, // Usage Minimum (0x01)
+ 0x29, 0x14, // Usage Maximum (0x14)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x04, // Report Count (4)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x45, 0x01, // Physical Maximum (1)
+ 0x09, 0x01, // Usage (0x01)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0xC0, // End Collection
+ 0xA1, 0x02, // Collection (Logical)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x07, // Report Count (7)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x46, 0xFF, 0x00, // Physical Maximum (255)
+ 0x09, 0x02, // Usage (0x02)
+ 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0xC0, // End Collection
+ 0xC0, // End Collection
+ };
+
+ BuzzState::BuzzState(u32 port_)
+ : port(port_)
+ {
+ }
+
+ BuzzState::~BuzzState() = default;
+
+ static void buzz_handle_control(USBDevice* dev, USBPacket* p,
+ int request, int value, int index, int length, uint8_t* data)
+ {
+ int ret = 0;
+
+ switch (request)
+ {
+ case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
+ switch (value >> 8)
+ {
+ case USB_DT_REPORT:
+ ret = sizeof(hid_report_descriptor);
+ memcpy(data, hid_report_descriptor, ret);
+ break;
+ }
+ break;
+ case SET_IDLE:
+ break;
+ default:
+ ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+ if (ret >= 0)
+ {
+ return;
+ }
+ p->status = USB_RET_STALL;
+ break;
+ }
+ }
+
+ static void buzz_handle_data(USBDevice* dev, USBPacket* p)
+ {
+ BuzzState* s = USB_CONTAINER_OF(dev, BuzzState, dev);
+
+ switch (p->pid)
+ {
+ case USB_TOKEN_IN:
+ if (p->ep->nr == 1)
+ {
+ pxAssert(p->buffer_size >= sizeof(s->data));
+
+ s->data.head1 = s->data.head2 = 0x7f;
+ s->data.tail = 0xf;
+
+ std::memcpy(p->buffer_ptr, &s->data, sizeof(s->data));
+
+ p->actual_length += sizeof(s->data);
+ }
+ else
+ {
+ goto fail;
+ }
+ break;
+ case USB_TOKEN_OUT:
+ break;
+ default:
+ fail:
+ p->status = USB_RET_STALL;
+ break;
+ }
+ }
+
+ static void buzz_unrealize(USBDevice* dev)
+ {
+ BuzzState* s = USB_CONTAINER_OF(dev, BuzzState, dev);
+ delete s;
+ }
+
+ const char* BuzzDevice::Name() const
+ {
+ return TRANSLATE_NOOP("USB", "Buzz Controller");
+ }
+
+ const char* BuzzDevice::TypeName() const
+ {
+ return "BuzzDevice";
+ }
+
+ USBDevice* BuzzDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
+ {
+ BuzzState* s = new BuzzState(port);
+
+ s->desc.full = &s->desc_dev;
+ s->desc.str = desc_strings;
+
+ if (usb_desc_parse_dev(dev_descriptor, sizeof(dev_descriptor), s->desc, s->desc_dev) < 0)
+ goto fail;
+ if (usb_desc_parse_config(config_descriptor, sizeof(config_descriptor), s->desc_dev) < 0)
+ goto fail;
+
+ s->dev.speed = USB_SPEED_FULL;
+ s->dev.klass.handle_attach = usb_desc_attach;
+ s->dev.klass.handle_reset = nullptr;
+ s->dev.klass.handle_control = buzz_handle_control;
+ s->dev.klass.handle_data = buzz_handle_data;
+ s->dev.klass.unrealize = buzz_unrealize;
+ s->dev.klass.usb_desc = &s->desc;
+ s->dev.klass.product_desc = nullptr;
+
+ usb_desc_init(&s->dev);
+ usb_ep_init(&s->dev);
+
+ return &s->dev;
+
+ fail:
+ buzz_unrealize(&s->dev);
+ return nullptr;
+ }
+
+ float BuzzDevice::GetBindingValue(const USBDevice* dev, u32 bind_index) const
+ {
+ BuzzState* s = USB_CONTAINER_OF(dev, BuzzState, dev);
+ switch (bind_index)
+ {
+ case CID_BUZZ_PLAYER1_RED: return s->data.player1_red;
+ case CID_BUZZ_PLAYER1_BLUE: return s->data.player1_blue;
+ case CID_BUZZ_PLAYER1_ORANGE: return s->data.player1_orange;
+ case CID_BUZZ_PLAYER1_GREEN: return s->data.player1_green;
+ case CID_BUZZ_PLAYER1_YELLOW: return s->data.player1_yellow;
+ case CID_BUZZ_PLAYER2_RED: return s->data.player2_red;
+ case CID_BUZZ_PLAYER2_BLUE: return s->data.player2_blue;
+ case CID_BUZZ_PLAYER2_ORANGE: return s->data.player2_orange;
+ case CID_BUZZ_PLAYER2_GREEN: return s->data.player2_green;
+ case CID_BUZZ_PLAYER2_YELLOW: return s->data.player2_yellow;
+ case CID_BUZZ_PLAYER3_RED: return s->data.player3_red;
+ case CID_BUZZ_PLAYER3_BLUE: return s->data.player3_blue;
+ case CID_BUZZ_PLAYER3_ORANGE: return s->data.player3_orange;
+ case CID_BUZZ_PLAYER3_GREEN: return s->data.player3_green;
+ case CID_BUZZ_PLAYER3_YELLOW: return s->data.player3_yellow;
+ case CID_BUZZ_PLAYER4_RED: return s->data.player4_red;
+ case CID_BUZZ_PLAYER4_BLUE: return s->data.player4_blue;
+ case CID_BUZZ_PLAYER4_ORANGE: return s->data.player4_orange;
+ case CID_BUZZ_PLAYER4_GREEN: return s->data.player4_green;
+ case CID_BUZZ_PLAYER4_YELLOW: return s->data.player4_yellow;
+ default:
+ return 0.0f;
+ }
+ }
+
+ void BuzzDevice::SetBindingValue(USBDevice* dev, u32 bind_index, float value) const
+ {
+ BuzzState* s = USB_CONTAINER_OF(dev, BuzzState, dev);
+ switch (bind_index)
+ {
+ case CID_BUZZ_PLAYER1_RED: s->data.player1_red = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER1_BLUE: s->data.player1_blue = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER1_ORANGE: s->data.player1_orange = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER1_GREEN: s->data.player1_green = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER1_YELLOW: s->data.player1_yellow = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER2_RED: s->data.player2_red = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER2_BLUE: s->data.player2_blue = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER2_ORANGE: s->data.player2_orange = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER2_GREEN: s->data.player2_green = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER2_YELLOW: s->data.player2_yellow = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER3_RED: s->data.player3_red = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER3_BLUE: s->data.player3_blue = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER3_ORANGE: s->data.player3_orange = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER3_GREEN: s->data.player3_green = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER3_YELLOW: s->data.player3_yellow = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER4_RED: s->data.player4_red = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER4_BLUE: s->data.player4_blue = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER4_ORANGE: s->data.player4_orange = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER4_GREEN: s->data.player4_green = (value >= 0.5f); break;
+ case CID_BUZZ_PLAYER4_YELLOW: s->data.player4_yellow = (value >= 0.5f); break;
+ default:
+ break;
+ }
+ }
+
+ std::span BuzzDevice::Bindings(u32 subtype) const
+ {
+ static constexpr const InputBindingInfo bindings[] = {
+ {"Red1", TRANSLATE_NOOP("USB", "Player 1 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER1_RED, GenericInputBinding::Circle},
+ {"Blue1", TRANSLATE_NOOP("USB", "Player 1 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER1_BLUE, GenericInputBinding::R1},
+ {"Orange1", TRANSLATE_NOOP("USB", "Player 1 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER1_ORANGE, GenericInputBinding::Cross},
+ {"Green1", TRANSLATE_NOOP("USB", "Player 1 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER1_GREEN, GenericInputBinding::Triangle},
+ {"Yellow1", TRANSLATE_NOOP("USB", "Player 1 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER1_YELLOW, GenericInputBinding::Square},
+
+ {"Red2", TRANSLATE_NOOP("USB", "Player 2 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER2_RED, GenericInputBinding::Unknown},
+ {"Blue2", TRANSLATE_NOOP("USB", "Player 2 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER2_BLUE, GenericInputBinding::Unknown},
+ {"Orange2", TRANSLATE_NOOP("USB", "Player 2 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER2_ORANGE, GenericInputBinding::Unknown},
+ {"Green2", TRANSLATE_NOOP("USB", "Player 2 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER2_GREEN, GenericInputBinding::Unknown},
+ {"Yellow2", TRANSLATE_NOOP("USB", "Player 2 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER2_YELLOW, GenericInputBinding::Unknown},
+
+ {"Red3", TRANSLATE_NOOP("USB", "Player 3 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER3_RED, GenericInputBinding::Unknown},
+ {"Blue3", TRANSLATE_NOOP("USB", "Player 3 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER3_BLUE, GenericInputBinding::Unknown},
+ {"Orange3", TRANSLATE_NOOP("USB", "Player 3 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER3_ORANGE, GenericInputBinding::Unknown},
+ {"Green3", TRANSLATE_NOOP("USB", "Player 3 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER3_GREEN, GenericInputBinding::Unknown},
+ {"Yellow3", TRANSLATE_NOOP("USB", "Player 3 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER3_YELLOW, GenericInputBinding::Unknown},
+
+ {"Red4", TRANSLATE_NOOP("USB", "Player 4 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER4_RED, GenericInputBinding::Unknown},
+ {"Blue4", TRANSLATE_NOOP("USB", "Player 4 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER4_BLUE, GenericInputBinding::Unknown},
+ {"Orange4", TRANSLATE_NOOP("USB", "Player 4 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER4_ORANGE, GenericInputBinding::Unknown},
+ {"Green4", TRANSLATE_NOOP("USB", "Player 4 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER4_GREEN, GenericInputBinding::Unknown},
+ {"Yellow4", TRANSLATE_NOOP("USB", "Player 4 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUZZ_PLAYER4_YELLOW, GenericInputBinding::Unknown},
+ };
+
+ return bindings;
+ }
+
+ std::span BuzzDevice::Settings(u32 subtype) const
+ {
+ return {};
+ }
+} // namespace usb_pad
diff --git a/pcsx2/USB/usb-pad/usb-buzz.h b/pcsx2/USB/usb-pad/usb-buzz.h
new file mode 100644
index 0000000000000..16c0ba8b66597
--- /dev/null
+++ b/pcsx2/USB/usb-pad/usb-buzz.h
@@ -0,0 +1,94 @@
+// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
+// SPDX-License-Identifier: LGPL-3.0+
+
+#pragma once
+#include "SaveState.h"
+#include "USB/qemu-usb/desc.h"
+#include
+#include
+
+namespace usb_pad
+{
+ enum BuzzControlID
+ {
+ CID_BUZZ_PLAYER1_RED,
+ CID_BUZZ_PLAYER1_BLUE,
+ CID_BUZZ_PLAYER1_ORANGE,
+ CID_BUZZ_PLAYER1_GREEN,
+ CID_BUZZ_PLAYER1_YELLOW,
+ CID_BUZZ_PLAYER2_RED,
+ CID_BUZZ_PLAYER2_BLUE,
+ CID_BUZZ_PLAYER2_ORANGE,
+ CID_BUZZ_PLAYER2_GREEN,
+ CID_BUZZ_PLAYER2_YELLOW,
+ CID_BUZZ_PLAYER3_RED,
+ CID_BUZZ_PLAYER3_BLUE,
+ CID_BUZZ_PLAYER3_ORANGE,
+ CID_BUZZ_PLAYER3_GREEN,
+ CID_BUZZ_PLAYER3_YELLOW,
+ CID_BUZZ_PLAYER4_RED,
+ CID_BUZZ_PLAYER4_BLUE,
+ CID_BUZZ_PLAYER4_ORANGE,
+ CID_BUZZ_PLAYER4_GREEN,
+ CID_BUZZ_PLAYER4_YELLOW,
+ CID_BUZZ_COUNT,
+ };
+
+ struct BuzzState
+ {
+ BuzzState(u32 port_);
+ ~BuzzState();
+
+ USBDevice dev{};
+ USBDesc desc{};
+ USBDescDevice desc_dev{};
+
+ u32 port = 0;
+
+ #pragma pack(push, 1)
+ struct
+ {
+ u8 head1;
+ u8 head2;
+
+ u8 player1_red : 1;
+ u8 player1_yellow : 1;
+ u8 player1_green : 1;
+ u8 player1_orange : 1;
+ u8 player1_blue : 1;
+ u8 player2_red : 1;
+ u8 player2_yellow : 1;
+ u8 player2_green : 1;
+
+ u8 player2_orange : 1;
+ u8 player2_blue : 1;
+ u8 player3_red : 1;
+ u8 player3_yellow : 1;
+ u8 player3_green : 1;
+ u8 player3_orange : 1;
+ u8 player3_blue : 1;
+ u8 player4_red : 1;
+
+ u8 player4_yellow : 1;
+ u8 player4_green : 1;
+ u8 player4_orange : 1;
+ u8 player4_blue : 1;
+
+ u8 tail : 4;
+ } data = {};
+ #pragma pack(pop)
+ };
+
+ class BuzzDevice final : public DeviceProxy
+ {
+ public:
+ const char* Name() const override;
+ const char* TypeName() const override;
+ float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
+ void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
+ std::span Bindings(u32 subtype) const override;
+ std::span Settings(u32 subtype) const override;
+ USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
+ };
+
+} // namespace usb_pad
diff --git a/pcsx2/USB/usb-pad/usb-pad.cpp b/pcsx2/USB/usb-pad/usb-pad.cpp
index 8a5c8e135d4e8..df7fa70b2fccc 100644
--- a/pcsx2/USB/usb-pad/usb-pad.cpp
+++ b/pcsx2/USB/usb-pad/usb-pad.cpp
@@ -37,12 +37,6 @@ namespace usb_pad
"Licensed by Sony Computer Entertainment America",
"Harmonix Drum Kit for PlayStation(R)3"};
- static const USBDescStrings buzz_desc_strings = {
- "",
- "Logitech Buzz(tm) Controller V1",
- "",
- "Logitech"};
-
static const USBDescStrings kbm_desc_strings = {
"",
"USB Multipurpose Controller",
@@ -339,18 +333,6 @@ namespace usb_pad
return len;
}
- case WT_BUZZ_CONTROLLER:
- {
- // https://gist.github.com/Lewiscowles1986/eef220dac6f0549e4702393a7b9351f6
- buf[0] = 0x7f;
- buf[1] = 0x7f;
- buf[2] = data.buttons & 0xff;
- buf[3] = (data.buttons >> 8) & 0xff;
- buf[4] = 0xf0 | ((data.buttons >> 16) & 0xf);
-
- return 5;
- }
-
case WT_SEGA_SEAMIC:
{
UpdateSteering();
@@ -695,11 +677,6 @@ namespace usb_pad
ret = sizeof(pad_driving_force_hid_separate_report_descriptor);
memcpy(data, pad_driving_force_hid_separate_report_descriptor, ret);
}
- else if (s->type == WT_BUZZ_CONTROLLER)
- {
- ret = sizeof(buzz_hid_report_descriptor);
- memcpy(data, buzz_hid_report_descriptor, ret);
- }
p->actual_length = ret;
break;
default:
@@ -951,80 +928,6 @@ namespace usb_pad
return {};
}
- // ---- Buzz ----
-
- const char* BuzzDevice::Name() const
- {
- return TRANSLATE_NOOP("USB", "Buzz Controller");
- }
-
- const char* BuzzDevice::TypeName() const
- {
- return "BuzzDevice";
- }
-
- std::span BuzzDevice::SubTypes() const
- {
- return {};
- }
-
- std::span BuzzDevice::Bindings(u32 subtype) const
- {
- static constexpr const InputBindingInfo bindings[] = {
- {"Red1", TRANSLATE_NOOP("USB", "Player 1 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::Circle},
- {"Blue1", TRANSLATE_NOOP("USB", "Player 1 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::R1},
- {"Orange1", TRANSLATE_NOOP("USB", "Player 1 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Cross},
- {"Green1", TRANSLATE_NOOP("USB", "Player 1 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Triangle},
- {"Yellow1", TRANSLATE_NOOP("USB", "Player 1 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Square},
-
- {"Red2", TRANSLATE_NOOP("USB", "Player 2 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON5, GenericInputBinding::Unknown},
- {"Blue2", TRANSLATE_NOOP("USB", "Player 2 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON9, GenericInputBinding::Unknown},
- {"Orange2", TRANSLATE_NOOP("USB", "Player 2 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON8, GenericInputBinding::Unknown},
- {"Green2", TRANSLATE_NOOP("USB", "Player 2 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON7, GenericInputBinding::Unknown},
- {"Yellow2", TRANSLATE_NOOP("USB", "Player 2 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON6, GenericInputBinding::Unknown},
-
- {"Red3", TRANSLATE_NOOP("USB", "Player 3 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON10, GenericInputBinding::Unknown},
- {"Blue3", TRANSLATE_NOOP("USB", "Player 3 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON14, GenericInputBinding::Unknown},
- {"Orange3", TRANSLATE_NOOP("USB", "Player 3 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON13, GenericInputBinding::Unknown},
- {"Green3", TRANSLATE_NOOP("USB", "Player 3 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON12, GenericInputBinding::Unknown},
- {"Yellow3", TRANSLATE_NOOP("USB", "Player 3 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON11, GenericInputBinding::Unknown},
-
- {"Red4", TRANSLATE_NOOP("USB", "Player 4 Red"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON15, GenericInputBinding::Unknown},
- {"Blue4", TRANSLATE_NOOP("USB", "Player 4 Blue"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON19, GenericInputBinding::Unknown},
- {"Orange4", TRANSLATE_NOOP("USB", "Player 4 Orange"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON18, GenericInputBinding::Unknown},
- {"Green4", TRANSLATE_NOOP("USB", "Player 4 Green"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON17, GenericInputBinding::Unknown},
- {"Yellow4", TRANSLATE_NOOP("USB", "Player 4 Yellow"), nullptr, InputBindingInfo::Type::Button, CID_BUTTON16, GenericInputBinding::Unknown},
- };
-
- return bindings;
- }
-
- std::span BuzzDevice::Settings(u32 subtype) const
- {
- return {};
- }
-
- USBDevice* BuzzDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
- {
- PadState* s = new PadState(port, WT_BUZZ_CONTROLLER);
-
- s->desc.full = &s->desc_dev;
- s->desc.str = buzz_desc_strings;
-
- if (usb_desc_parse_dev(buzz_dev_descriptor, sizeof(buzz_dev_descriptor), s->desc, s->desc_dev) < 0)
- goto fail;
- if (usb_desc_parse_config(buzz_config_descriptor, sizeof(buzz_config_descriptor), s->desc_dev) < 0)
- goto fail;
-
- pad_init(s);
-
- return &s->dev;
-
- fail:
- pad_handle_destroy(&s->dev);
- return nullptr;
- }
-
// ---- Keyboardmania ----
const char* KeyboardmaniaDevice::Name() const
diff --git a/pcsx2/USB/usb-pad/usb-pad.h b/pcsx2/USB/usb-pad/usb-pad.h
index 0fc2681714299..f05eb9cc5a897 100644
--- a/pcsx2/USB/usb-pad/usb-pad.h
+++ b/pcsx2/USB/usb-pad/usb-pad.h
@@ -61,7 +61,6 @@ namespace usb_pad
WT_DRIVING_FORCE_PRO_1102, //hw with buggy hid report?
WT_GT_FORCE, //formula gp
WT_ROCKBAND1_DRUMKIT,
- WT_BUZZ_CONTROLLER,
WT_SEGA_SEAMIC,
WT_KEYBOARDMANIA_CONTROLLER,
WT_COUNT,
@@ -95,17 +94,6 @@ namespace usb_pad
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
};
- class BuzzDevice final : public PadDevice
- {
- public:
- const char* Name() const;
- const char* TypeName() const;
- std::span SubTypes() const;
- std::span Bindings(u32 subtype) const;
- std::span Settings(u32 subtype) const;
- USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const;
- };
-
class SeamicDevice final : public PadDevice
{
public:
@@ -1108,105 +1096,6 @@ namespace usb_pad
// 137 bytes
};
- //////////
- // Buzz //
- //////////
-
- static const uint8_t buzz_dev_descriptor[] = {
- 0x12, // bLength
- 0x01, // bDescriptorType (Device)
- 0x00, 0x02, // bcdUSB 2.00
- 0x00, // bDeviceClass (Use class information in the Interface Descriptors)
- 0x00, // bDeviceSubClass
- 0x00, // bDeviceProtocol
- 0x08, // bMaxPacketSize0 8
- 0x4C, 0x05, // idVendor 0x054C
- 0x02, 0x00, // idProduct 0x0002
- 0xA1, 0x05, // bcdDevice 11.01
- 0x03, // iManufacturer (String Index)
- 0x01, // iProduct (String Index)
- 0x00, // iSerialNumber (String Index)
- 0x01, // bNumConfigurations 1
- };
-
- static const uint8_t buzz_config_descriptor[] = {
- 0x09, // bLength
- 0x02, // bDescriptorType (Configuration)
- 0x22, 0x00, // wTotalLength 34
- 0x01, // bNumInterfaces 1
- 0x01, // bConfigurationValue
- 0x00, // iConfiguration (String Index)
- 0x80, // bmAttributes
- 0x32, // bMaxPower 100mA
-
- 0x09, // bLength
- 0x04, // bDescriptorType (Interface)
- 0x00, // bInterfaceNumber 0
- 0x00, // bAlternateSetting
- 0x01, // bNumEndpoints 1
- 0x03, // bInterfaceClass
- 0x00, // bInterfaceSubClass
- 0x00, // bInterfaceProtocol
- 0x00, // iInterface (String Index)
-
- 0x09, // bLength
- 0x21, // bDescriptorType (HID)
- 0x11, 0x01, // bcdHID 1.11
- 0x33, // bCountryCode
- 0x01, // bNumDescriptors
- 0x22, // bDescriptorType[0] (HID)
- 0x4E, 0x00, // wDescriptorLength[0] 78
-
- 0x07, // bLength
- 0x05, // bDescriptorType (Endpoint)
- 0x81, // bEndpointAddress (IN/D2H)
- 0x03, // bmAttributes (Interrupt)
- 0x08, 0x00, // wMaxPacketSize 8
- 0x0A, // bInterval 10 (unit depends on device speed)
- };
-
- static const uint8_t buzz_hid_report_descriptor[] = {
- 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
- 0x09, 0x04, // Usage (Joystick)
- 0xA1, 0x01, // Collection (Application)
- 0xA1, 0x02, // Collection (Logical)
- 0x75, 0x08, // Report Size (8)
- 0x95, 0x02, // Report Count (2)
- 0x15, 0x00, // Logical Minimum (0)
- 0x26, 0xFF, 0x00, // Logical Maximum (255)
- 0x35, 0x00, // Physical Minimum (0)
- 0x46, 0xFF, 0x00, // Physical Maximum (255)
- 0x09, 0x30, // Usage (X)
- 0x09, 0x31, // Usage (Y)
- 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x75, 0x01, // Report Size (1)
- 0x95, 0x14, // Report Count (20)
- 0x25, 0x01, // Logical Maximum (1)
- 0x45, 0x01, // Physical Maximum (1)
- 0x05, 0x09, // Usage Page (Button)
- 0x19, 0x01, // Usage Minimum (0x01)
- 0x29, 0x14, // Usage Maximum (0x14)
- 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
- 0x75, 0x01, // Report Size (1)
- 0x95, 0x04, // Report Count (4)
- 0x25, 0x01, // Logical Maximum (1)
- 0x45, 0x01, // Physical Maximum (1)
- 0x09, 0x01, // Usage (0x01)
- 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0xC0, // End Collection
- 0xA1, 0x02, // Collection (Logical)
- 0x75, 0x08, // Report Size (8)
- 0x95, 0x07, // Report Count (7)
- 0x26, 0xFF, 0x00, // Logical Maximum (255)
- 0x46, 0xFF, 0x00, // Physical Maximum (255)
- 0x09, 0x02, // Usage (0x02)
- 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
- 0xC0, // End Collection
- 0xC0, // End Collection
- // 78 bytes
- };
-
///////////////////
// Keyboardmania //
///////////////////
diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj
index f9b0f83eab342..a0c70b5e14b48 100644
--- a/pcsx2/pcsx2.vcxproj
+++ b/pcsx2/pcsx2.vcxproj
@@ -392,6 +392,7 @@
+
@@ -842,6 +843,7 @@
+
diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters
index 27b0cd06f16e4..bc919af5c5b3a 100644
--- a/pcsx2/pcsx2.vcxproj.filters
+++ b/pcsx2/pcsx2.vcxproj.filters
@@ -1187,6 +1187,9 @@
System\Ps2\USB\usb-hid
+
+ System\Ps2\USB\usb-pad
+
System\Ps2\USB\usb-pad
@@ -2130,6 +2133,9 @@
System\Ps2\USB\usb-hid
+
+ System\Ps2\USB\usb-pad
+
System\Ps2\USB\usb-pad