diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index a8b55808ab..941553287d 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -348,6 +348,7 @@ target_sources(rpcs3_emu PRIVATE Io/PadHandler.cpp Io/usb_device.cpp Io/Skylander.cpp + Io/GHLtar.cpp ) diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index 43ce5c90db..ab396ee798 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -11,6 +11,7 @@ #include "Emu/Io/usb_device.h" #include "Emu/Io/Skylander.h" +#include "Emu/Io/GHLtar.h" #include @@ -139,6 +140,7 @@ usb_handler_thread::usb_handler_thread() ssize_t ndev = libusb_get_device_list(ctx, &list); bool found_skylander = false; + bool found_ghltar = false; 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(0x12BA, 0x0100, 0x0100, "Guitar Hero Guitar"); 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, 0x0200, 0x020F, "Harmonix Guitar"); check_device(0x12BA, 0x0210, 0x021F, "Harmonix Drums"); @@ -198,6 +201,12 @@ usb_handler_thread::usb_handler_thread() usb_devices.push_back(std::make_shared()); } + if (!found_ghltar) + { + sys_usbd.notice("Adding emulated GHLtar"); + usb_devices.push_back(std::make_shared()); + } + for (u32 index = 0; index < MAX_SYS_USBD_TRANSFERS; index++) { transfers[index].transfer = libusb_alloc_transfer(8); @@ -448,7 +457,7 @@ error_code sys_usbd_initialize(vm::ptr handle) // Must not occur (lv2 allows multiple handles, cellUsbd does not) verify("sys_usbd Initialized twice" HERE), !usbh->is_init.exchange(true); - *handle = 0x115B; + *handle = 0x115B; // TODO return CELL_OK; @@ -500,8 +509,8 @@ error_code sys_usbd_get_device_list(u32 handle, vm::ptr devic error_code sys_usbd_register_extra_ldd(u32 handle, vm::ptr 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)", - handle, s_product, slen_product, id_vendor, id_product_min, 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)", handle, s_product, slen_product, id_vendor, + id_product_min, id_product_max); const auto usbh = g_fxo->get>(); @@ -566,8 +575,7 @@ error_code sys_usbd_unregister_ldd() // 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) { - 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); + 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); const auto usbh = g_fxo->get>(); diff --git a/rpcs3/Emu/Io/GHLtar.cpp b/rpcs3/Emu/Io/GHLtar.cpp new file mode 100644 index 0000000000..e9bfc3b033 --- /dev/null +++ b/rpcs3/Emu/Io/GHLtar.cpp @@ -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; + } + } +} diff --git a/rpcs3/Emu/Io/GHLtar.h b/rpcs3/Emu/Io/GHLtar.h new file mode 100644 index 0000000000..db7d707ad5 --- /dev/null +++ b/rpcs3/Emu/Io/GHLtar.h @@ -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; +}; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 017cfde63b..e5ebfbbde7 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -69,6 +69,7 @@ + @@ -420,6 +421,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index dd6b05fcc6..38d60c01d6 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -881,6 +881,9 @@ Emu\GPU\RSX\Overlays\Shaders + + Emu\Io + Emu\Cell\lv2 @@ -1735,5 +1738,8 @@ Emu\GPU\RSX\Overlays + + Emu\Io + \ No newline at end of file