mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
sys_usbd: Guitar Hero Live controller emulation (#7336)
* Initial GHLtar emulation * Add GHLtar to CMakeLists and VS project, zero the buffer and remove unused header values * Fix coding style issues and include headers * Remove redundant if, improve code formatting * Remove needless includes Co-authored-by: Ivan <Nekotekina@users.noreply.github.com>
This commit is contained in:
parent
7e590eaa2f
commit
ef6854ca46
@ -348,6 +348,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||||||
Io/PadHandler.cpp
|
Io/PadHandler.cpp
|
||||||
Io/usb_device.cpp
|
Io/usb_device.cpp
|
||||||
Io/Skylander.cpp
|
Io/Skylander.cpp
|
||||||
|
Io/GHLtar.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "Emu/Io/usb_device.h"
|
#include "Emu/Io/usb_device.h"
|
||||||
#include "Emu/Io/Skylander.h"
|
#include "Emu/Io/Skylander.h"
|
||||||
|
#include "Emu/Io/GHLtar.h"
|
||||||
|
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ usb_handler_thread::usb_handler_thread()
|
|||||||
ssize_t ndev = libusb_get_device_list(ctx, &list);
|
ssize_t ndev = libusb_get_device_list(ctx, &list);
|
||||||
|
|
||||||
bool found_skylander = false;
|
bool found_skylander = false;
|
||||||
|
bool found_ghltar = false;
|
||||||
|
|
||||||
for (ssize_t index = 0; index < ndev; index++)
|
for (ssize_t index = 0; index < ndev; index++)
|
||||||
{
|
{
|
||||||
@ -167,7 +169,8 @@ usb_handler_thread::usb_handler_thread()
|
|||||||
check_device(0x1415, 0x0000, 0x0000, "Singstar Microphone");
|
check_device(0x1415, 0x0000, 0x0000, "Singstar Microphone");
|
||||||
check_device(0x12BA, 0x0100, 0x0100, "Guitar Hero Guitar");
|
check_device(0x12BA, 0x0100, 0x0100, "Guitar Hero Guitar");
|
||||||
check_device(0x12BA, 0x0120, 0x0120, "Guitar Hero Drums");
|
check_device(0x12BA, 0x0120, 0x0120, "Guitar Hero Drums");
|
||||||
check_device(0x12BA, 0x074B, 0x074B, "Guitar Hero Live Guitar");
|
found_ghltar = check_device(0x12BA, 0x074B, 0x074B, "Guitar Hero Live Guitar");
|
||||||
|
|
||||||
check_device(0x12BA, 0x0140, 0x0140, "DJ Hero Turntable");
|
check_device(0x12BA, 0x0140, 0x0140, "DJ Hero Turntable");
|
||||||
check_device(0x12BA, 0x0200, 0x020F, "Harmonix Guitar");
|
check_device(0x12BA, 0x0200, 0x020F, "Harmonix Guitar");
|
||||||
check_device(0x12BA, 0x0210, 0x021F, "Harmonix Drums");
|
check_device(0x12BA, 0x0210, 0x021F, "Harmonix Drums");
|
||||||
@ -198,6 +201,12 @@ usb_handler_thread::usb_handler_thread()
|
|||||||
usb_devices.push_back(std::make_shared<usb_device_skylander>());
|
usb_devices.push_back(std::make_shared<usb_device_skylander>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found_ghltar)
|
||||||
|
{
|
||||||
|
sys_usbd.notice("Adding emulated GHLtar");
|
||||||
|
usb_devices.push_back(std::make_shared<usb_device_ghltar>());
|
||||||
|
}
|
||||||
|
|
||||||
for (u32 index = 0; index < MAX_SYS_USBD_TRANSFERS; index++)
|
for (u32 index = 0; index < MAX_SYS_USBD_TRANSFERS; index++)
|
||||||
{
|
{
|
||||||
transfers[index].transfer = libusb_alloc_transfer(8);
|
transfers[index].transfer = libusb_alloc_transfer(8);
|
||||||
@ -448,7 +457,7 @@ error_code sys_usbd_initialize(vm::ptr<u32> handle)
|
|||||||
// Must not occur (lv2 allows multiple handles, cellUsbd does not)
|
// Must not occur (lv2 allows multiple handles, cellUsbd does not)
|
||||||
verify("sys_usbd Initialized twice" HERE), !usbh->is_init.exchange(true);
|
verify("sys_usbd Initialized twice" HERE), !usbh->is_init.exchange(true);
|
||||||
|
|
||||||
*handle = 0x115B;
|
*handle = 0x115B;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
@ -500,8 +509,8 @@ error_code sys_usbd_get_device_list(u32 handle, vm::ptr<UsbInternalDevice> devic
|
|||||||
|
|
||||||
error_code sys_usbd_register_extra_ldd(u32 handle, vm::ptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max)
|
error_code sys_usbd_register_extra_ldd(u32 handle, vm::ptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max)
|
||||||
{
|
{
|
||||||
sys_usbd.warning("sys_usbd_register_extra_ldd(handle=0x%x, s_product=%s, slen_product=0x%x, id_vendor=0x%x, id_product_min=0x%x, id_product_max=0x%x)",
|
sys_usbd.warning("sys_usbd_register_extra_ldd(handle=0x%x, s_product=%s, slen_product=0x%x, id_vendor=0x%x, id_product_min=0x%x, id_product_max=0x%x)", handle, s_product, slen_product, id_vendor,
|
||||||
handle, s_product, slen_product, id_vendor, id_product_min, id_product_max);
|
id_product_min, id_product_max);
|
||||||
|
|
||||||
const auto usbh = g_fxo->get<named_thread<usb_handler_thread>>();
|
const auto usbh = g_fxo->get<named_thread<usb_handler_thread>>();
|
||||||
|
|
||||||
@ -566,8 +575,7 @@ error_code sys_usbd_unregister_ldd()
|
|||||||
// TODO: determine what the unknown params are
|
// TODO: determine what the unknown params are
|
||||||
error_code sys_usbd_open_pipe(u32 handle, u32 device_handle, u32 unk1, u64 unk2, u64 unk3, u32 endpoint, u64 unk4)
|
error_code sys_usbd_open_pipe(u32 handle, u32 device_handle, u32 unk1, u64 unk2, u64 unk3, u32 endpoint, u64 unk4)
|
||||||
{
|
{
|
||||||
sys_usbd.warning("sys_usbd_open_pipe(handle=0x%x, device_handle=0x%x, unk1=0x%x, unk2=0x%x, unk3=0x%x, endpoint=0x%x, unk4=0x%x)",
|
sys_usbd.warning("sys_usbd_open_pipe(handle=0x%x, device_handle=0x%x, unk1=0x%x, unk2=0x%x, unk3=0x%x, endpoint=0x%x, unk4=0x%x)", handle, device_handle, unk1, unk2, unk3, endpoint, unk4);
|
||||||
handle, device_handle, unk1, unk2, unk3, endpoint, unk4);
|
|
||||||
|
|
||||||
const auto usbh = g_fxo->get<named_thread<usb_handler_thread>>();
|
const auto usbh = g_fxo->get<named_thread<usb_handler_thread>>();
|
||||||
|
|
||||||
|
215
rpcs3/Emu/Io/GHLtar.cpp
Normal file
215
rpcs3/Emu/Io/GHLtar.cpp
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
// Guitar Hero Live controller emulator
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "GHLtar.h"
|
||||||
|
#include "Emu/Cell/lv2/sys_usbd.h"
|
||||||
|
#include "Input/pad_thread.h"
|
||||||
|
|
||||||
|
LOG_CHANNEL(ghltar_log);
|
||||||
|
|
||||||
|
usb_device_ghltar::usb_device_ghltar()
|
||||||
|
{
|
||||||
|
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0x00, 0x00, 0x00, 0x20, 0x12BA, 0x074B, 0x0100, 0x01, 0x02, 0x00, 0x01});
|
||||||
|
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x0029, 0x01, 0x01, 0x00, 0x80, 0x96}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 0x001d}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0020, 0x01}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x01, 0x03, 0x0020, 0x01}));
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_device_ghltar::~usb_device_ghltar()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_device_ghltar::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:
|
||||||
|
ghltar_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_ghltar::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(6ms, TODO accurate measurement)
|
||||||
|
transfer->expected_time = get_timestamp() + 6000;
|
||||||
|
|
||||||
|
memset(buf, 0, buf_size);
|
||||||
|
|
||||||
|
buf[0] = 0x00; // Frets
|
||||||
|
// FRET HEXMASK:
|
||||||
|
// 0x02 = B1
|
||||||
|
// 0x04 = B2
|
||||||
|
// 0x08 = B3
|
||||||
|
// 0x01 = W1
|
||||||
|
// 0x10 = W2
|
||||||
|
// 0x20 = W3
|
||||||
|
|
||||||
|
buf[1] = 0x00; // Buttons
|
||||||
|
// BUTTONS HEXMASK:
|
||||||
|
// 0x01 = Select/Hero Power
|
||||||
|
// 0x02 = Start/Pause
|
||||||
|
// 0x04 = GHTV Button
|
||||||
|
// 0x10 = Sync Button
|
||||||
|
|
||||||
|
buf[2] = 0x0F; // D-Pad
|
||||||
|
// DPAD VALUES:
|
||||||
|
// 0x00 = Up
|
||||||
|
// 0x01 = Up-Left
|
||||||
|
// 0x02 = Left
|
||||||
|
// 0x03 = Left-Down
|
||||||
|
// 0x04 = Down
|
||||||
|
// 0x05 = Down-Right
|
||||||
|
// 0x06 = Right
|
||||||
|
// 0x07 = Up-Right
|
||||||
|
// 0x0F = None
|
||||||
|
|
||||||
|
buf[4] = 0x80; // Strummer
|
||||||
|
|
||||||
|
buf[5] = 0x80; // Hero Power (when buf[19] == 0x00 or 0xFF, set to that.)
|
||||||
|
buf[6] = 0x80; // Whammy
|
||||||
|
buf[19] = 0x80; // Accelerometer
|
||||||
|
|
||||||
|
buf[3] = 0x80; // Unknown, always 0x80
|
||||||
|
buf[22] = 0x01; // Unknown, always 0x01
|
||||||
|
buf[24] = 0x02; // Unknown, always 0x02
|
||||||
|
buf[26] = 0x02; // Unknown, always 0x02
|
||||||
|
// buf[7] through buf[18] are always 0x00
|
||||||
|
// buf[21]/[23]/[25] are also 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 (Button& button : pad->m_buttons)
|
||||||
|
{
|
||||||
|
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
|
||||||
|
{
|
||||||
|
if (button.m_pressed)
|
||||||
|
pad->m_digital_2 |= button.m_outKeyCode;
|
||||||
|
else
|
||||||
|
pad->m_digital_2 &= ~button.m_outKeyCode;
|
||||||
|
|
||||||
|
switch (button.m_outKeyCode)
|
||||||
|
{
|
||||||
|
case CELL_PAD_CTRL_SQUARE:
|
||||||
|
pad->m_press_square = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[0] += 0x01; // W1
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_CROSS:
|
||||||
|
pad->m_press_cross = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[0] += 0x02; // B1
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_CIRCLE:
|
||||||
|
pad->m_press_circle = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[0] += 0x04; // B2
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_TRIANGLE:
|
||||||
|
pad->m_press_triangle = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[0] += 0x08; // B3
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_R1:
|
||||||
|
pad->m_press_R1 = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[0] += 0x20; // W3
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_L1:
|
||||||
|
pad->m_press_L1 = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[0] += 0x10; // W2
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
|
||||||
|
{
|
||||||
|
if (button.m_pressed)
|
||||||
|
pad->m_digital_1 |= button.m_outKeyCode;
|
||||||
|
else
|
||||||
|
pad->m_digital_1 &= ~button.m_outKeyCode;
|
||||||
|
|
||||||
|
switch (button.m_outKeyCode)
|
||||||
|
{
|
||||||
|
case CELL_PAD_CTRL_DOWN:
|
||||||
|
pad->m_press_down = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[4] = 0xFF; // Strum Down
|
||||||
|
buf[2] = 0x04; // Down D-Pad (Unused)
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_UP:
|
||||||
|
pad->m_press_up = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[4] = 0x00; // Strum Up
|
||||||
|
buf[2] = 0x00; // Up D-Pad (Unused)
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_LEFT:
|
||||||
|
pad->m_press_down = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[2] = 0x02; // Left D-Pad (Unused)
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_RIGHT:
|
||||||
|
pad->m_press_up = button.m_value;
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[2] = 0x06; // Right D-Pad (Unused)
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_START:
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[1] += 0x02; // Pause
|
||||||
|
break;
|
||||||
|
case CELL_PAD_CTRL_SELECT:
|
||||||
|
if (button.m_pressed)
|
||||||
|
buf[1] += 0x01; // Hero Power
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const AnalogStick& stick : pad->m_sticks)
|
||||||
|
{
|
||||||
|
switch (stick.m_offset)
|
||||||
|
{
|
||||||
|
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y:
|
||||||
|
buf[6] = ~(stick.m_value) + 0x01; // Whammy
|
||||||
|
pad->m_analog_right_x = stick.m_value;
|
||||||
|
break;
|
||||||
|
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
|
||||||
|
buf[19] = stick.m_value; // Tilt
|
||||||
|
if (buf[19] >= 0xF0)
|
||||||
|
buf[5] = 0xFF;
|
||||||
|
if (buf[19] <= 0x10)
|
||||||
|
buf[5] = 0x00;
|
||||||
|
pad->m_analog_right_y = stick.m_value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
rpcs3/Emu/Io/GHLtar.h
Normal file
13
rpcs3/Emu/Io/GHLtar.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Emu/Io/usb_device.h"
|
||||||
|
|
||||||
|
class usb_device_ghltar : public usb_device_emulated
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
usb_device_ghltar();
|
||||||
|
~usb_device_ghltar();
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
@ -69,6 +69,7 @@
|
|||||||
</PreBuildEvent>
|
</PreBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Emu\Io\GHLtar.cpp" />
|
||||||
<ClCompile Include="Emu\Audio\AudioBackend.cpp" />
|
<ClCompile Include="Emu\Audio\AudioBackend.cpp" />
|
||||||
<ClCompile Include="Emu\Io\KeyboardHandler.cpp" />
|
<ClCompile Include="Emu\Io\KeyboardHandler.cpp" />
|
||||||
<ClCompile Include="Emu\Io\pad_config.cpp" />
|
<ClCompile Include="Emu\Io\pad_config.cpp" />
|
||||||
@ -420,6 +421,7 @@
|
|||||||
<ClInclude Include="Emu\Cell\Modules\cellRemotePlay.h" />
|
<ClInclude Include="Emu\Cell\Modules\cellRemotePlay.h" />
|
||||||
<ClInclude Include="Emu\Cell\Modules\cellSsl.h" />
|
<ClInclude Include="Emu\Cell\Modules\cellSsl.h" />
|
||||||
<ClInclude Include="Emu\Cell\Modules\cellStorage.h" />
|
<ClInclude Include="Emu\Cell\Modules\cellStorage.h" />
|
||||||
|
<ClInclude Include="Emu\Io\GHLtar.h" />
|
||||||
<ClInclude Include="Emu\Io\pad_types.h" />
|
<ClInclude Include="Emu\Io\pad_types.h" />
|
||||||
<ClInclude Include="Emu\Io\Keyboard.h" />
|
<ClInclude Include="Emu\Io\Keyboard.h" />
|
||||||
<ClInclude Include="Emu\Io\pad_config.h" />
|
<ClInclude Include="Emu\Io\pad_config.h" />
|
||||||
|
@ -881,6 +881,9 @@
|
|||||||
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp">
|
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp">
|
||||||
<Filter>Emu\GPU\RSX\Overlays\Shaders</Filter>
|
<Filter>Emu\GPU\RSX\Overlays\Shaders</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\Io\GHLtar.cpp">
|
||||||
|
<Filter>Emu\Io</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\Cell\lv2\sys_crypto_engine.cpp">
|
<ClCompile Include="Emu\Cell\lv2\sys_crypto_engine.cpp">
|
||||||
<Filter>Emu\Cell\lv2</Filter>
|
<Filter>Emu\Cell\lv2</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -1735,5 +1738,8 @@
|
|||||||
<ClInclude Include="Emu\RSX\Overlays\overlay_shader_compile_notification.h">
|
<ClInclude Include="Emu\RSX\Overlays\overlay_shader_compile_notification.h">
|
||||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Io\GHLtar.h">
|
||||||
|
<Filter>Emu\Io</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue
Block a user