mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
sys_usbd: DJ Hero Turntable Emulation (#9965)
* Initial Turntable Emulation
This commit is contained in:
parent
f93dbb8f49
commit
6a14849381
@ -369,6 +369,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Io/Skylander.cpp
|
||||
Io/GHLtar.cpp
|
||||
Io/Buzz.cpp
|
||||
Io/Turntable.cpp
|
||||
)
|
||||
|
||||
# Np
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "Emu/Io/Skylander.h"
|
||||
#include "Emu/Io/GHLtar.h"
|
||||
#include "Emu/Io/Buzz.h"
|
||||
#include "Emu/Io/Turntable.h"
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
@ -145,6 +146,7 @@ usb_handler_thread::usb_handler_thread()
|
||||
|
||||
bool found_skylander = false;
|
||||
bool found_ghltar = false;
|
||||
bool found_turntable = false;
|
||||
|
||||
for (ssize_t index = 0; index < ndev; index++)
|
||||
{
|
||||
@ -182,7 +184,10 @@ usb_handler_thread::usb_handler_thread()
|
||||
found_ghltar = true;
|
||||
}
|
||||
|
||||
check_device(0x12BA, 0x0140, 0x0140, "DJ Hero Turntable");
|
||||
if (check_device(0x12BA, 0x0140, 0x0140, "DJ Hero Turntable"))
|
||||
{
|
||||
found_turntable = true;
|
||||
}
|
||||
check_device(0x12BA, 0x0200, 0x020F, "Harmonix Guitar");
|
||||
check_device(0x12BA, 0x0210, 0x021F, "Harmonix Drums");
|
||||
check_device(0x12BA, 0x2330, 0x233F, "Harmonix Keyboard");
|
||||
@ -228,6 +233,12 @@ usb_handler_thread::usb_handler_thread()
|
||||
usb_devices.push_back(std::make_shared<usb_device_ghltar>());
|
||||
}
|
||||
|
||||
if (!found_turntable)
|
||||
{
|
||||
sys_usbd.notice("Adding emulated turntable");
|
||||
usb_devices.push_back(std::make_shared<usb_device_turntable>());
|
||||
}
|
||||
|
||||
if (g_cfg.io.buzz == buzz_handler::one_controller || g_cfg.io.buzz == buzz_handler::two_controllers)
|
||||
{
|
||||
sys_usbd.notice("Adding emulated Buzz! buzzer (1-4 players)");
|
||||
|
269
rpcs3/Emu/Io/Turntable.cpp
Normal file
269
rpcs3/Emu/Io/Turntable.cpp
Normal file
@ -0,0 +1,269 @@
|
||||
// DJ Hero Turntable controller emulator
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Turntable.h"
|
||||
#include "Emu/Cell/lv2/sys_usbd.h"
|
||||
#include "Input/pad_thread.h"
|
||||
|
||||
LOG_CHANNEL(turntable_log);
|
||||
|
||||
usb_device_turntable::usb_device_turntable()
|
||||
{
|
||||
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0100, 0x00, 0x00, 0x00, 0x40, 0x12BA, 0x0140, 0x0005, 0x01, 0x02, 0x00, 0x01});
|
||||
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x0029, 0x01, 0x01, 0x00, 0x80, 0x19}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0110, 0x00, 0x01, 0x22, 0x0089}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0040, 0x0a}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x0040, 0x0a}));
|
||||
}
|
||||
|
||||
usb_device_turntable::~usb_device_turntable()
|
||||
{
|
||||
}
|
||||
|
||||
void usb_device_turntable::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 0x21:
|
||||
switch (bRequest)
|
||||
{
|
||||
case 0x09:
|
||||
// Do nothing here - not sure what it should do.
|
||||
break;
|
||||
default:
|
||||
turntable_log.error("Unhandled Query Type: 0x%02X", buf[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer)
|
||||
{
|
||||
transfer->fake = true;
|
||||
transfer->expected_count = buf_size;
|
||||
transfer->expected_result = HC_CC_NOERR;
|
||||
// Interrupt transfers are slow
|
||||
// Turntable runs at 100hz --> 10ms
|
||||
transfer->expected_time = get_timestamp() + 10000;
|
||||
|
||||
memset(buf, 0, buf_size);
|
||||
|
||||
buf[0] = 0x00; // Face Buttons
|
||||
// FACE BUTTON HEXMASK:
|
||||
// 0x01 = Square
|
||||
// 0x02 = Cross
|
||||
// 0x04 = Circle
|
||||
// 0x08 = Triangle / Euphoria
|
||||
|
||||
buf[1] = 0x00; // Start/Select Buttons
|
||||
// START/SELECT HEXMASK:
|
||||
// 0x01 = Select
|
||||
// 0x02 = Start
|
||||
// 0x10 = PS Button
|
||||
|
||||
buf[2] = 0x0F; // D-Pad
|
||||
// DPAD VALUES:
|
||||
// 0x00 = Up
|
||||
// 0x01 = Up-Right
|
||||
// 0x02 = Right
|
||||
// 0x03 = Right-Down
|
||||
// 0x04 = Down
|
||||
// 0x05 = Down-Left
|
||||
// 0x06 = Left
|
||||
// 0x07 = Up-Left
|
||||
// 0x0F = None
|
||||
|
||||
buf[3] = 0x80; // Unknown, always 0x80
|
||||
buf[4] = 0x80; // Unknown, always 0x80
|
||||
|
||||
buf[5] = 0x80; // Left Turntable
|
||||
buf[6] = 0x80; // Right Turntable
|
||||
|
||||
// The following bytes are NOTed (set to 0xFF) when active.
|
||||
// If multiple buttons are pressed for one byte, the byte is NOTed twice (reset to 0x00).
|
||||
buf[7] = 0x00; // Square Button / D-Pad Right
|
||||
buf[8] = 0x00; // D-Pad Left
|
||||
buf[9] = 0x00; // Cross Button / D-Pad Up
|
||||
buf[10] = 0x00; // D-Pad Down
|
||||
buf[11] = 0x00; // Triangle / Euphoria Button
|
||||
buf[12] = 0x00; // Circle Button
|
||||
|
||||
buf[19] = 0x00; // Effects Dial, lower 8 bits
|
||||
buf[20] = 0x02; // Effects Dial, upper 2 bits
|
||||
|
||||
buf[21] = 0x00; // Crossfader, lower 8 bits
|
||||
buf[22] = 0x02; // Crossfader, upper 2 bits
|
||||
|
||||
buf[23] = 0x00; // Platter Buttons
|
||||
// PLATTER BUTTON VALUES:
|
||||
// 0x01 = Right Platter, Green
|
||||
// 0x02 = Right Platter, Red
|
||||
// 0x04 = Right Platter, Blue
|
||||
// 0x10 = Left Platter, Green
|
||||
// 0x20 = Left Platter, Red
|
||||
// 0x40 = Left Platter, Blue
|
||||
|
||||
buf[24] = 0x02; // Unknown, always 0x02
|
||||
buf[26] = 0x02; // Unknown, always 0x02
|
||||
|
||||
// All other bufs are always 0x00
|
||||
|
||||
const auto handler = pad::get_current_handler();
|
||||
const auto& pads = handler->GetPads();
|
||||
const auto pad = pads[6];
|
||||
|
||||
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
|
||||
return;
|
||||
|
||||
for (const Button& button : pad->m_buttons)
|
||||
{
|
||||
if (button.m_pressed)
|
||||
{
|
||||
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
|
||||
{
|
||||
switch (button.m_outKeyCode)
|
||||
{
|
||||
case CELL_PAD_CTRL_SQUARE:
|
||||
buf[0] |= 0x01; // Square Button
|
||||
buf[7] = ~buf[7]; // Square Button
|
||||
buf[23] |= 0x04; // Right Platter Blue
|
||||
break;
|
||||
case CELL_PAD_CTRL_CROSS:
|
||||
buf[0] |= 0x02; // Cross Button
|
||||
buf[9] = ~buf[9]; // Cross Button
|
||||
buf[23] |= 0x01; // Right Platter Green
|
||||
break;
|
||||
case CELL_PAD_CTRL_CIRCLE:
|
||||
buf[0] |= 0x04; // Circle Button
|
||||
buf[12] = ~buf[12]; // Circle Button
|
||||
buf[23] |= 0x02; // Right Platter Red
|
||||
break;
|
||||
case CELL_PAD_CTRL_TRIANGLE:
|
||||
buf[0] |= 0x08; // Triangle Button / Euphoria
|
||||
buf[11] = ~buf[11]; // Triangle Button / Euphoria
|
||||
break;
|
||||
case CELL_PAD_CTRL_R1:
|
||||
buf[0] |= 0x02; // Cross Button Only
|
||||
buf[9] = ~buf[9]; // Cross Button Only
|
||||
break;
|
||||
case CELL_PAD_CTRL_L1:
|
||||
buf[0] |= 0x04; // Circle Button Only
|
||||
buf[12] = ~buf[12]; // Circle Button Only
|
||||
break;
|
||||
case CELL_PAD_CTRL_R2:
|
||||
buf[0] |= 0x01; // Square Button Only
|
||||
buf[7] = ~buf[7]; // Square Button Only
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
|
||||
{
|
||||
switch (button.m_outKeyCode)
|
||||
{
|
||||
case CELL_PAD_CTRL_DOWN:
|
||||
if (buf[2] == 0x02) // Right D-Pad
|
||||
{
|
||||
buf[2] = 0x03; // Right-Down D-Pad
|
||||
}
|
||||
else if (buf[2] == 0x06) // Left D-Pad
|
||||
{
|
||||
buf[2] = 0x05; // Left-Down D-Pad
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[2] = 0x04; // Down D-Pad
|
||||
}
|
||||
buf[10] = ~buf[10]; // Down D-Pad;
|
||||
break;
|
||||
case CELL_PAD_CTRL_UP:
|
||||
if (buf[2] == 0x02) // Right D-Pad
|
||||
{
|
||||
buf[2] = 0x01; // Right-Up D-Pad
|
||||
}
|
||||
else if (buf[2] == 0x06) // Left D-Pad
|
||||
{
|
||||
buf[2] = 0x07; // Left-Up D-Pad
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[2] = 0x00; // Up D-Pad
|
||||
}
|
||||
buf[9] = ~buf[9]; // Up D-Pad;
|
||||
break;
|
||||
case CELL_PAD_CTRL_LEFT:
|
||||
if (buf[2] == 0x00) // Up D-Pad
|
||||
{
|
||||
buf[2] = 0x07; // Left-Up D-Pad
|
||||
}
|
||||
else if (buf[2] == 0x04) // Down D-Pad
|
||||
{
|
||||
buf[2] = 0x05; // Left-Down D-Pad
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[2] = 0x06; // Left D-Pad
|
||||
}
|
||||
buf[8] = ~buf[8]; // Left D-Pad;
|
||||
break;
|
||||
case CELL_PAD_CTRL_RIGHT:
|
||||
if (buf[2] == 0x00) // Up D-Pad
|
||||
{
|
||||
buf[2] = 0x01; // Right-Up D-Pad
|
||||
}
|
||||
else if (buf[2] == 0x04) // Down D-Pad
|
||||
{
|
||||
buf[2] = 0x03; // Right-Down D-Pad
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[2] = 0x02; // Right D-Pad
|
||||
}
|
||||
buf[7] = ~buf[7]; // Right D-Pad
|
||||
break;
|
||||
case CELL_PAD_CTRL_START:
|
||||
buf[1] |= 0x02; // Start
|
||||
break;
|
||||
case CELL_PAD_CTRL_SELECT:
|
||||
buf[1] |= 0x01; // Select
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const AnalogStick& stick : pad->m_sticks)
|
||||
{
|
||||
switch (stick.m_offset)
|
||||
{
|
||||
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y:
|
||||
buf[6] = ~(stick.m_value) + 0x01; // Right Turntable
|
||||
// Some pad handlers like MMJoystick are centered at 0x81 instead of 0x80
|
||||
// which leaves the turntable stuck at 0x7F instead of 0x80, causing auto-scrolling menus
|
||||
// so force 0x7F to 0x80.
|
||||
if (buf[6] == 0x7F)
|
||||
buf[6] = 0x80;
|
||||
break;
|
||||
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y:
|
||||
buf[21] = (stick.m_value & 0x3F) << 2; // Crossfader, lower 6 bits
|
||||
buf[22] = (stick.m_value & 0xC0) >> 6; // Crossfader, upper 2 bits
|
||||
break;
|
||||
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
|
||||
buf[19] = (stick.m_value & 0x3F) << 2; // Effects Dial, lower 6 bits
|
||||
buf[20] = (stick.m_value & 0xC0) >> 6; // Effects Dial, upper 2 bits
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
13
rpcs3/Emu/Io/Turntable.h
Normal file
13
rpcs3/Emu/Io/Turntable.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Io/usb_device.h"
|
||||
|
||||
class usb_device_turntable : public usb_device_emulated
|
||||
{
|
||||
public:
|
||||
usb_device_turntable();
|
||||
~usb_device_turntable();
|
||||
|
||||
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;
|
||||
};
|
@ -76,6 +76,7 @@
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\Modules\sys_crashdump.cpp" />
|
||||
<ClCompile Include="Emu\Io\Turntable.cpp" />
|
||||
<ClCompile Include="Emu\Io\GHLtar.cpp" />
|
||||
<ClCompile Include="Emu\Io\Buzz.cpp" />
|
||||
<ClCompile Include="Emu\Audio\AudioBackend.cpp" />
|
||||
@ -451,6 +452,7 @@
|
||||
<ClInclude Include="Emu\Cell\Modules\cellSsl.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\cellStorage.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\sys_crashdump.h" />
|
||||
<ClInclude Include="Emu\Io\Turntable.h" />
|
||||
<ClInclude Include="Emu\Io\GHLtar.h" />
|
||||
<ClInclude Include="Emu\Io\Buzz.h" />
|
||||
<ClInclude Include="Emu\Io\interception.h" />
|
||||
|
@ -986,6 +986,9 @@
|
||||
<ClCompile Include="Emu\Cell\Modules\sys_crashdump.cpp">
|
||||
<Filter>Emu\Cell\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Io\Turntable.cpp">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
@ -1921,6 +1924,9 @@
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache_types.h">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Io\Turntable.h">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Loader\mself.hpp">
|
||||
<Filter>Loader</Filter>
|
||||
</ClInclude>
|
||||
|
Loading…
x
Reference in New Issue
Block a user