From eda6be746f50f08de0bce2f85f115dafc888914f Mon Sep 17 00:00:00 2001 From: ElBread3 <92335081+ElBread3@users.noreply.github.com> Date: Fri, 31 Oct 2025 09:11:14 +0000 Subject: [PATCH] usbd: Implement usb backend system (#3737) * initial impl * reviews * upstreamed deReaperJosh changes * fixed config.cpp --------- Co-authored-by: georgemoralis --- CMakeLists.txt | 1 + src/common/config.cpp | 14 + src/common/config.h | 4 + src/core/ipc/ipc.cpp | 38 ++ src/core/libraries/usbd/usb_backend.h | 477 ++++++++++++++++++++++++++ src/core/libraries/usbd/usbd.cpp | 117 +++---- src/core/libraries/usbd/usbd.h | 8 + 7 files changed, 597 insertions(+), 62 deletions(-) create mode 100644 src/core/libraries/usbd/usb_backend.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 14ad3e3fc..40aeaa991 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -532,6 +532,7 @@ set(RANDOM_LIB src/core/libraries/random/random.cpp set(USBD_LIB src/core/libraries/usbd/usbd.cpp src/core/libraries/usbd/usbd.h + src/core/libraries/usbd/usb_backend.h ) set(FIBER_LIB src/core/libraries/fiber/fiber_context.s diff --git a/src/common/config.cpp b/src/common/config.cpp index 539c4242e..4d3e1d877 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -208,6 +208,9 @@ std::filesystem::path save_data_path = {}; // Settings ConfigEntry m_language(1); // english +// USB Device +static ConfigEntry usbDeviceBackend(UsbBackendType::Real); + // Keys static string trophyKey = ""; @@ -817,6 +820,14 @@ void setRcasAttenuation(int value, bool is_game_specific) { rcasAttenuation.set(value, is_game_specific); } +int getUsbDeviceBackend() { + return usbDeviceBackend.get(); +} + +void setUsbDeviceBackend(int value, bool is_game_specific) { + usbDeviceBackend.set(value, is_game_specific); +} + bool getLoadAutoPatches() { return load_auto_patches; } @@ -881,6 +892,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) { isMotionControlsEnabled.setFromToml(input, "isMotionControlsEnabled", is_game_specific); useUnifiedInputConfig.setFromToml(input, "useUnifiedInputConfig", is_game_specific); backgroundControllerInput.setFromToml(input, "backgroundControllerInput", is_game_specific); + usbDeviceBackend.setFromToml(input, "usbDeviceBackend", is_game_specific); } if (data.contains("Audio")) { @@ -1063,6 +1075,7 @@ void save(const std::filesystem::path& path, bool is_game_specific) { is_game_specific); backgroundControllerInput.setTomlValue(data, "Input", "backgroundControllerInput", is_game_specific); + usbDeviceBackend.setTomlValue(data, "Input", "usbDeviceBackend", is_game_specific); micDevice.setTomlValue(data, "Audio", "micDevice", is_game_specific); mainOutputDevice.setTomlValue(data, "Audio", "mainOutputDevice", is_game_specific); @@ -1194,6 +1207,7 @@ void setDefaultValues(bool is_game_specific) { cursorHideTimeout.set(5, is_game_specific); isMotionControlsEnabled.set(true, is_game_specific); backgroundControllerInput.set(false, is_game_specific); + usbDeviceBackend.set(UsbBackendType::Real, is_game_specific); // GS - Audio micDevice.set("Default Device", is_game_specific); diff --git a/src/common/config.h b/src/common/config.h index 43bdf83f3..5c9f89ae6 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -151,6 +151,10 @@ void setSysModulesPath(const std::filesystem::path& path); bool getLoadAutoPatches(); void setLoadAutoPatches(bool enable); +enum UsbBackendType : int { Real, SkylandersPortal, InfinityBase, DimensionsToypad }; +int getUsbDeviceBackend(); +void setUsbDeviceBackend(int value, bool is_game_specific = false); + // TODO std::filesystem::path GetSaveDataPath(); std::string getUserName(); diff --git a/src/core/ipc/ipc.cpp b/src/core/ipc/ipc.cpp index 0f416982d..e334ff712 100644 --- a/src/core/ipc/ipc.cpp +++ b/src/core/ipc/ipc.cpp @@ -17,6 +17,7 @@ #include "core/libraries/audio/audioout.h" #include "input/input_handler.h" #include "sdl_window.h" +#include "src/core/libraries/usbd/usbd.h" #include "video_core/renderer_vulkan/vk_presenter.h" extern std::unique_ptr presenter; @@ -169,6 +170,43 @@ void IPC::InputLoop() { presenter->GetFsrSettingsRef().rcas_attenuation = static_cast(value / 1000.0f); } + } else if (cmd == "USB_LOAD_FIGURE") { + const auto ref = Libraries::Usbd::usb_backend->GetImplRef(); + if (ref) { + const std::string& file_name = next_str(); + const u8 pad = next_u64(); + const u8 slot = next_u64(); + ref->LoadFigure(file_name, pad, slot); + } + } else if (cmd == "USB_REMOVE_FIGURE") { + const auto ref = Libraries::Usbd::usb_backend->GetImplRef(); + if (ref) { + const u8 pad = next_u64(); + const u8 slot = next_u64(); + const bool full_remove = next_u64() != 0; + ref->RemoveFigure(pad, slot, full_remove); + } + } else if (cmd == "USB_MOVE_FIGURE") { + const auto ref = Libraries::Usbd::usb_backend->GetImplRef(); + if (ref) { + const u8 new_pad = next_u64(); + const u8 new_index = next_u64(); + const u8 old_pad = next_u64(); + const u8 old_index = next_u64(); + ref->MoveFigure(new_pad, new_index, old_pad, old_index); + } + } else if (cmd == "USB_TEMP_REMOVE_FIGURE") { + const auto ref = Libraries::Usbd::usb_backend->GetImplRef(); + if (ref) { + const u8 index = next_u64(); + ref->TempRemoveFigure(index); + } + } else if (cmd == "USB_CANCEL_REMOVE_FIGURE") { + const auto ref = Libraries::Usbd::usb_backend->GetImplRef(); + if (ref) { + const u8 index = next_u64(); + ref->CancelRemoveFigure(index); + } } else if (cmd == "RELOAD_INPUTS") { std::string config = next_str(); Input::ParseInputConfig(config); diff --git a/src/core/libraries/usbd/usb_backend.h b/src/core/libraries/usbd/usb_backend.h new file mode 100644 index 000000000..7a5c2899a --- /dev/null +++ b/src/core/libraries/usbd/usb_backend.h @@ -0,0 +1,477 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include + +#include "common/assert.h" +#include "common/types.h" + +namespace Libraries::Usbd { + +#if defined(_WIN32) +typedef CRITICAL_SECTION usbi_mutex_t; +#else +typedef pthread_mutex_t usbi_mutex_t; +#endif + +struct list_head { + struct list_head *prev, *next; +}; + +// Forward declared libusb structs +struct UsbDeviceHandle { + usbi_mutex_t lock; + unsigned long claimed_interfaces; + struct list_head list; + struct libusb_device* dev; + int auto_detach_kernel_driver; +}; + +struct UsbDevice { + volatile long refcnt; + + struct libusb_context* ctx; + struct libusb_device* parent_dev; + + u8 bus_number; + u8 port_number; + u8 device_address; + enum libusb_speed speed; + + struct list_head list; + unsigned long session_data; + + struct libusb_device_descriptor device_descriptor; + volatile long attached; +}; + +class UsbEmulatedImpl { +public: + UsbEmulatedImpl() = default; + + virtual void LoadFigure(std::string file_name, u8 pad, u8 slot) = 0; + virtual void RemoveFigure(u8 pad, u8 slot, bool full_remove) = 0; + virtual void MoveFigure(u8 new_pad, u8 new_index, u8 old_pad, u8 old_index) = 0; + virtual void TempRemoveFigure(u8 index) = 0; + virtual void CancelRemoveFigure(u8 index) = 0; + +protected: + virtual ~UsbEmulatedImpl() = default; +}; + +class UsbBackend { +public: + UsbBackend() = default; + + virtual s32 Init() = 0; + virtual void Exit() = 0; + + virtual s64 GetDeviceList(libusb_device*** list) = 0; + virtual void FreeDeviceList(libusb_device** list, s32 unref_devices) = 0; + + virtual s32 GetConfiguration(libusb_device_handle* dev, s32* config) = 0; + virtual s32 GetDeviceDescriptor(libusb_device* dev, libusb_device_descriptor* desc) = 0; + virtual s32 GetActiveConfigDescriptor(libusb_device* dev, + libusb_config_descriptor** config) = 0; + virtual s32 GetConfigDescriptor(libusb_device* dev, u8 config_index, + libusb_config_descriptor** config) = 0; + virtual void FreeConfigDescriptor(libusb_config_descriptor* config) = 0; + + virtual u8 GetBusNumber(libusb_device* dev) = 0; + virtual u8 GetDeviceAddress(libusb_device* dev) = 0; + virtual s32 GetMaxPacketSize(libusb_device* dev, u8 endpoint) = 0; + + virtual s32 OpenDevice(libusb_device* dev, libusb_device_handle** dev_handle) = 0; + virtual void CloseDevice(libusb_device_handle* dev_handle) = 0; + virtual libusb_device* GetDevice(libusb_device_handle* dev_handle) = 0; + + virtual s32 SetConfiguration(libusb_device_handle* dev_handle, s32 configuration) = 0; + virtual s32 ClaimInterface(libusb_device_handle* dev_handle, s32 interface_number) = 0; + virtual libusb_device_handle* OpenDeviceWithVidPid(u16 vendor_id, u16 product_id) = 0; + virtual s32 ResetDevice(libusb_device_handle* dev_handle) = 0; + + virtual s32 KernelDriverActive(libusb_device_handle* dev_handle, s32 interface_number) = 0; + virtual s32 DetachKernelDriver(libusb_device_handle* dev_handle, s32 interface_number) = 0; + virtual s32 AttachKernelDriver(libusb_device_handle* dev_handle, s32 interface_number) = 0; + + virtual s32 ControlTransfer(libusb_device_handle* dev_handle, u8 bmRequestType, u8 bRequest, + u16 wValue, u16 wIndex, u8* data, u16 wLength, u32 timeout) = 0; + virtual s32 SubmitTransfer(libusb_transfer* transfer) = 0; + + virtual s32 TryLockEvents() = 0; + virtual void LockEvents() = 0; + virtual void UnlockEvents() = 0; + virtual s32 EventHandlingOk() = 0; + virtual s32 EventHandlerActive() = 0; + virtual void LockEventWaiters() = 0; + virtual void UnlockEventWaiters() = 0; + virtual s32 WaitForEvent(timeval* tv) = 0; + + virtual s32 HandleEventsTimeout(timeval* tv) = 0; + virtual s32 HandleEvents() = 0; + virtual s32 HandleEventsLocked(timeval* tv) = 0; + + virtual s32 CheckConnected(libusb_device_handle* dev) = 0; + virtual std::shared_ptr GetImplRef() = 0; + +protected: + virtual ~UsbBackend() = default; +}; + +class UsbRealBackend : public UsbBackend { +public: + s32 Init() override { + return libusb_init(&g_libusb_context); + } + void Exit() override { + libusb_exit(g_libusb_context); + } + + s64 GetDeviceList(libusb_device*** list) override { + return libusb_get_device_list(g_libusb_context, list); + } + void FreeDeviceList(libusb_device** list, s32 unref_devices) override { + libusb_free_device_list(list, unref_devices); + } + + s32 GetConfiguration(libusb_device_handle* dev, s32* config) override { + return libusb_get_configuration(dev, config); + } + s32 GetDeviceDescriptor(libusb_device* dev, libusb_device_descriptor* desc) override { + return libusb_get_device_descriptor(dev, desc); + } + s32 GetActiveConfigDescriptor(libusb_device* dev, libusb_config_descriptor** config) override { + return libusb_get_active_config_descriptor(dev, config); + } + s32 GetConfigDescriptor(libusb_device* dev, u8 config_index, + libusb_config_descriptor** config) override { + return libusb_get_config_descriptor(dev, config_index, config); + } + void FreeConfigDescriptor(libusb_config_descriptor* config) override { + libusb_free_config_descriptor(config); + } + + u8 GetBusNumber(libusb_device* dev) override { + return libusb_get_bus_number(dev); + } + u8 GetDeviceAddress(libusb_device* dev) override { + return libusb_get_device_address(dev); + } + s32 GetMaxPacketSize(libusb_device* dev, u8 endpoint) override { + return libusb_get_max_packet_size(dev, endpoint); + } + + s32 OpenDevice(libusb_device* dev, libusb_device_handle** dev_handle) override { + return libusb_open(dev, dev_handle); + } + void CloseDevice(libusb_device_handle* dev_handle) override { + libusb_close(dev_handle); + } + libusb_device* GetDevice(libusb_device_handle* dev_handle) override { + return libusb_get_device(dev_handle); + } + + s32 SetConfiguration(libusb_device_handle* dev_handle, s32 configuration) override { + return libusb_set_configuration(dev_handle, configuration); + } + s32 ClaimInterface(libusb_device_handle* dev_handle, s32 interface_number) override { + return libusb_claim_interface(dev_handle, interface_number); + } + libusb_device_handle* OpenDeviceWithVidPid(u16 vendor_id, u16 product_id) override { + return libusb_open_device_with_vid_pid(g_libusb_context, vendor_id, product_id); + } + s32 ResetDevice(libusb_device_handle* dev_handle) override { + return libusb_reset_device(dev_handle); + } + + s32 KernelDriverActive(libusb_device_handle* dev_handle, s32 interface_number) override { +#if defined(_WIN32) || defined(__APPLE__) + return s_has_removed_driver ? 0 : 1; +#else + return libusb_kernel_driver_active(dev_handle, interface_number); +#endif + } + s32 DetachKernelDriver(libusb_device_handle* dev_handle, s32 interface_number) override { +#if defined(_WIN32) || defined(__APPLE__) + s_has_removed_driver = true; + return LIBUSB_SUCCESS; +#else + return libusb_detach_kernel_driver(dev_handle, interface_number); +#endif + } + s32 AttachKernelDriver(libusb_device_handle* dev_handle, s32 interface_number) override { +#if defined(_WIN32) || defined(__APPLE__) + s_has_removed_driver = false; + return LIBUSB_SUCCESS; +#else + return libusb_attach_kernel_driver(dev_handle, interface_number); +#endif + } + + s32 ControlTransfer(libusb_device_handle* dev_handle, u8 bmRequestType, u8 bRequest, u16 wValue, + u16 wIndex, u8* data, u16 wLength, u32 timeout) override { + return libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, data, + wLength, timeout); + } + s32 SubmitTransfer(libusb_transfer* transfer) override { + return libusb_submit_transfer(transfer); + } + + s32 TryLockEvents() override { + return libusb_try_lock_events(g_libusb_context); + } + void LockEvents() override { + return libusb_lock_events(g_libusb_context); + } + void UnlockEvents() override { + return libusb_unlock_events(g_libusb_context); + } + s32 EventHandlingOk() override { + return libusb_event_handling_ok(g_libusb_context); + } + s32 EventHandlerActive() override { + return libusb_event_handler_active(g_libusb_context); + } + void LockEventWaiters() override { + return libusb_lock_event_waiters(g_libusb_context); + } + void UnlockEventWaiters() override { + return libusb_unlock_event_waiters(g_libusb_context); + } + s32 WaitForEvent(timeval* tv) override { + return libusb_wait_for_event(g_libusb_context, tv); + } + + s32 HandleEventsTimeout(timeval* tv) override { + return libusb_handle_events_timeout(g_libusb_context, tv); + } + s32 HandleEvents() override { + return libusb_handle_events(g_libusb_context); + } + s32 HandleEventsLocked(timeval* tv) override { + return libusb_handle_events_locked(g_libusb_context, tv); + } + + s32 CheckConnected(libusb_device_handle* dev) override { + // There's no libusb version of this function. + // Simulate by querying data. + + int config; + return libusb_get_configuration(dev, &config); + } + + std::shared_ptr GetImplRef() override { + return nullptr; + } + +protected: + libusb_context* g_libusb_context = nullptr; + bool s_has_removed_driver = false; +}; + +class UsbEmulatedBackend : public UsbRealBackend { +public: + s64 GetDeviceList(libusb_device*** list) override { + auto** fake = static_cast(calloc(2, sizeof(libusb_device*))); + fake[0] = GetDevice(nullptr); + fake[1] = nullptr; + *list = fake; + + return 1; + } + void FreeDeviceList(libusb_device** list, s32 unref_devices) override { + if (!list) { + return; + } + + if (unref_devices) { + int i = 0; + libusb_device* dev; + + while ((dev = list[i++]) != nullptr) { + free(dev); + } + } + free(list); + } + + s32 GetConfiguration(libusb_device_handle* dev, s32* config) override { + config = nullptr; + return LIBUSB_SUCCESS; + } + + s32 GetDeviceDescriptor(libusb_device* dev, libusb_device_descriptor* desc) override { + std::memcpy(desc, FillDeviceDescriptor(), sizeof(libusb_device_descriptor)); + return LIBUSB_SUCCESS; + } + s32 GetActiveConfigDescriptor(libusb_device* dev, libusb_config_descriptor** config) override { + const auto endpoint_descs = FillEndpointDescriptorPair(); + const auto interface_desc = FillInterfaceDescriptor(endpoint_descs); + + const auto interface = static_cast(calloc(1, sizeof(libusb_interface*))); + interface->altsetting = interface_desc; + interface->num_altsetting = 1; + + const auto new_config = FillConfigDescriptor(interface); + + ASSERT(endpoint_descs && interface_desc && new_config); + *config = new_config; + return LIBUSB_SUCCESS; + } + s32 GetConfigDescriptor(libusb_device* dev, u8 config_index, + libusb_config_descriptor** config) override { + if (config_index >= 1) { + return LIBUSB_ERROR_NOT_FOUND; + } + return GetActiveConfigDescriptor(dev, config); + } + void FreeConfigDescriptor(libusb_config_descriptor* config) override { + // Member variable reference, don't free + } + + u8 GetBusNumber(libusb_device* dev) override { + return 0; + } + u8 GetDeviceAddress(libusb_device* dev) override { + return 0; + } + s32 GetMaxPacketSize(libusb_device* dev, u8 endpoint) override { + libusb_device_descriptor* desc = nullptr; + + int r = GetDeviceDescriptor(dev, desc); + if (r < LIBUSB_SUCCESS) { + return LIBUSB_ERROR_OTHER; + } + return desc->bMaxPacketSize0; + } + + s32 OpenDevice(libusb_device* dev, libusb_device_handle** dev_handle) override { + auto* _dev_handle = static_cast(calloc(1, sizeof(libusb_device_handle*))); + if (!_dev_handle) { + return LIBUSB_ERROR_NO_MEM; + } + _dev_handle->dev = dev; + *dev_handle = reinterpret_cast(_dev_handle); + return LIBUSB_SUCCESS; + } + void CloseDevice(libusb_device_handle* dev_handle) override { + LOG_WARNING(Lib_Usbd, "Guest decided to close device, might be an implementation issue"); + free(dev_handle); + } + libusb_device* GetDevice(libusb_device_handle* dev_handle) override { + const auto desc = FillDeviceDescriptor(); + ASSERT(desc); + + const auto fake = static_cast(calloc(1, sizeof(UsbDevice*))); + fake->bus_number = 0; + fake->port_number = 0; + fake->device_address = 0; + fake->device_descriptor = *desc; + fake->ctx = g_libusb_context; + return reinterpret_cast(fake); + } + + s32 SetConfiguration(libusb_device_handle* dev_handle, s32 configuration) override { + return LIBUSB_SUCCESS; + } + s32 ClaimInterface(libusb_device_handle* dev_handle, s32 interface_number) override { + return LIBUSB_SUCCESS; + } + libusb_device_handle* OpenDeviceWithVidPid(u16 vendor_id, u16 product_id) override { + libusb_device_handle* dev_handle = nullptr; + OpenDevice(GetDevice(nullptr), &dev_handle); + return dev_handle; + } + s32 ResetDevice(libusb_device_handle* dev_handle) override { + LOG_WARNING(Lib_Usbd, "Guest decided to reset device, might be an implementation issue"); + return LIBUSB_SUCCESS; + } + + s32 KernelDriverActive(libusb_device_handle* dev_handle, s32 interface_number) override { + return s_has_removed_driver ? 0 : 1; + } + s32 DetachKernelDriver(libusb_device_handle* dev_handle, s32 interface_number) override { + s_has_removed_driver = true; + return LIBUSB_SUCCESS; + } + s32 AttachKernelDriver(libusb_device_handle* dev_handle, s32 interface_number) override { + s_has_removed_driver = false; + return LIBUSB_SUCCESS; + } + + s32 ControlTransfer(libusb_device_handle* dev_handle, u8 bmRequestType, u8 bRequest, u16 wValue, + u16 wIndex, u8* data, u16 wLength, u32 timeout) override { + LOG_WARNING(Lib_Usbd, "Backend has not handled control transfers"); + return LIBUSB_ERROR_PIPE; + } + s32 SubmitTransfer(libusb_transfer* transfer) override { + ASSERT(transfer->type == LIBUSB_TRANSFER_TYPE_INTERRUPT); + + // if we have no other flying transfers, start the list with this one + if (flight_list.empty()) { + flight_list.push_front(transfer); + return LIBUSB_SUCCESS; + } + + // if we have infinite timeout, append to end of list + if (transfer->timeout == 0) { + flight_list.push_back(transfer); + return LIBUSB_SUCCESS; + } + + // otherwise, find appropriate place in list + for (auto it = flight_list.begin(); it != flight_list.end(); ++it) { + if ((*it)->timeout > transfer->timeout) { + flight_list.insert(it, transfer); + return LIBUSB_SUCCESS; + } + } + + // otherwise we need to be inserted at the end + flight_list.push_back(transfer); + return LIBUSB_SUCCESS; + } + + s32 HandleEventsTimeout(timeval* tv) override { + return HandleEvents(); + } + s32 HandleEvents() override { + if (!flight_list.empty()) { + const auto transfer = flight_list.front(); + + const u8 flags = transfer->flags; + transfer->status = HandleAsyncTransfer(transfer); + transfer->actual_length = transfer->length; + if (transfer->callback) { + transfer->callback(transfer); + } + if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) { + libusb_free_transfer(transfer); + } + flight_list.pop_front(); + } + + return LIBUSB_SUCCESS; + } + + s32 CheckConnected(libusb_device_handle* dev) override { + return LIBUSB_SUCCESS; + } + +protected: + virtual libusb_endpoint_descriptor* FillEndpointDescriptorPair() = 0; + virtual libusb_interface_descriptor* FillInterfaceDescriptor( + libusb_endpoint_descriptor* descs) = 0; + virtual libusb_config_descriptor* FillConfigDescriptor(libusb_interface* inter) = 0; + virtual libusb_device_descriptor* FillDeviceDescriptor() = 0; + + virtual libusb_transfer_status HandleAsyncTransfer(libusb_transfer* transfer) = 0; + + std::list flight_list; +}; + +} // namespace Libraries::Usbd diff --git a/src/core/libraries/usbd/usbd.cpp b/src/core/libraries/usbd/usbd.cpp index 730646ea1..0708c3dd7 100644 --- a/src/core/libraries/usbd/usbd.cpp +++ b/src/core/libraries/usbd/usbd.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" -#include "common/singleton.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "usbd.h" @@ -10,6 +9,8 @@ #include #include +#include "common/config.h" + namespace Libraries::Usbd { s32 libusb_to_orbis_error(int retVal) { @@ -23,7 +24,7 @@ s32 libusb_to_orbis_error(int retVal) { return retVal; } -libusb_context* g_libusb_context; +std::shared_ptr usb_backend; #if defined(_WIN32) bool s_has_removed_driver = false; @@ -32,25 +33,25 @@ bool s_has_removed_driver = false; s32 PS4_SYSV_ABI sceUsbdInit() { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_init(&g_libusb_context)); + return libusb_to_orbis_error(usb_backend->Init()); } void PS4_SYSV_ABI sceUsbdExit() { LOG_DEBUG(Lib_Usbd, "called"); - libusb_exit(g_libusb_context); + usb_backend->Exit(); } s64 PS4_SYSV_ABI sceUsbdGetDeviceList(SceUsbdDevice*** list) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_get_device_list(g_libusb_context, list)); + return libusb_to_orbis_error(usb_backend->GetDeviceList(list)); } void PS4_SYSV_ABI sceUsbdFreeDeviceList(SceUsbdDevice** list, s32 unref_devices) { LOG_DEBUG(Lib_Usbd, "called"); - libusb_free_device_list(list, unref_devices); + usb_backend->FreeDeviceList(list, unref_devices); } SceUsbdDevice* PS4_SYSV_ABI sceUsbdRefDevice(SceUsbdDevice* device) { @@ -68,27 +69,27 @@ void PS4_SYSV_ABI sceUsbdUnrefDevice(SceUsbdDevice* device) { s32 PS4_SYSV_ABI sceUsbdGetConfiguration(SceUsbdDeviceHandle* dev_handle, s32* config) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_get_configuration(dev_handle, config)); + return libusb_to_orbis_error(usb_backend->GetConfiguration(dev_handle, config)); } s32 PS4_SYSV_ABI sceUsbdGetDeviceDescriptor(SceUsbdDevice* device, SceUsbdDeviceDescriptor* desc) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_get_device_descriptor(device, desc)); + return libusb_to_orbis_error(usb_backend->GetDeviceDescriptor(device, desc)); } s32 PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor(SceUsbdDevice* device, SceUsbdConfigDescriptor** config) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_get_active_config_descriptor(device, config)); + return libusb_to_orbis_error(usb_backend->GetActiveConfigDescriptor(device, config)); } s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptor(SceUsbdDevice* device, u8 config_index, SceUsbdConfigDescriptor** config) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_get_config_descriptor(device, config_index, config)); + return libusb_to_orbis_error(usb_backend->GetConfigDescriptor(device, config_index, config)); } s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue(SceUsbdDevice* device, u8 bConfigurationValue, @@ -102,19 +103,19 @@ s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue(SceUsbdDevice* device, u8 bCo void PS4_SYSV_ABI sceUsbdFreeConfigDescriptor(SceUsbdConfigDescriptor* config) { LOG_DEBUG(Lib_Usbd, "called"); - libusb_free_config_descriptor(config); + usb_backend->FreeConfigDescriptor(config); } u8 PS4_SYSV_ABI sceUsbdGetBusNumber(SceUsbdDevice* device) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_get_bus_number(device); + return usb_backend->GetBusNumber(device); } u8 PS4_SYSV_ABI sceUsbdGetDeviceAddress(SceUsbdDevice* device) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_get_device_address(device); + return usb_backend->GetDeviceAddress(device); } SceUsbdSpeed PS4_SYSV_ABI sceUsbdGetDeviceSpeed(SceUsbdDevice* device) { @@ -126,7 +127,7 @@ SceUsbdSpeed PS4_SYSV_ABI sceUsbdGetDeviceSpeed(SceUsbdDevice* device) { s32 PS4_SYSV_ABI sceUsbdGetMaxPacketSize(SceUsbdDevice* device, u8 endpoint) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_get_max_packet_size(device, endpoint)); + return libusb_to_orbis_error(usb_backend->GetMaxPacketSize(device, endpoint)); } s32 PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize(SceUsbdDevice* device, u8 endpoint) { @@ -138,25 +139,25 @@ s32 PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize(SceUsbdDevice* device, u8 endpoint) s32 PS4_SYSV_ABI sceUsbdOpen(SceUsbdDevice* device, SceUsbdDeviceHandle** dev_handle) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_open(device, dev_handle)); + return libusb_to_orbis_error(usb_backend->OpenDevice(device, dev_handle)); } void PS4_SYSV_ABI sceUsbdClose(SceUsbdDeviceHandle* dev_handle) { LOG_DEBUG(Lib_Usbd, "called"); - libusb_close(dev_handle); + usb_backend->CloseDevice(dev_handle); } SceUsbdDevice* PS4_SYSV_ABI sceUsbdGetDevice(SceUsbdDeviceHandle* dev_handle) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_get_device(dev_handle); + return usb_backend->GetDevice(dev_handle); } s32 PS4_SYSV_ABI sceUsbdSetConfiguration(SceUsbdDeviceHandle* dev_handle, s32 config) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_set_configuration(dev_handle, config)); + return libusb_to_orbis_error(usb_backend->SetConfiguration(dev_handle, config)); } s32 PS4_SYSV_ABI sceUsbdClaimInterface(SceUsbdDeviceHandle* dev_handle, s32 interface_number) { @@ -166,7 +167,7 @@ s32 PS4_SYSV_ABI sceUsbdClaimInterface(SceUsbdDeviceHandle* dev_handle, s32 inte sceUsbdDetachKernelDriver(dev_handle, interface_number); } - return libusb_to_orbis_error(libusb_claim_interface(dev_handle, interface_number)); + return libusb_to_orbis_error(usb_backend->ClaimInterface(dev_handle, interface_number)); } s32 PS4_SYSV_ABI sceUsbdReleaseInterface(SceUsbdDeviceHandle* dev_handle, s32 interface_number) { @@ -178,7 +179,7 @@ s32 PS4_SYSV_ABI sceUsbdReleaseInterface(SceUsbdDeviceHandle* dev_handle, s32 in SceUsbdDeviceHandle* PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid(u16 vendor_id, u16 product_id) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_open_device_with_vid_pid(g_libusb_context, vendor_id, product_id); + return usb_backend->OpenDeviceWithVidPid(vendor_id, product_id); } s32 PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting(SceUsbdDeviceHandle* dev_handle, @@ -198,42 +199,25 @@ s32 PS4_SYSV_ABI sceUsbdClearHalt(SceUsbdDeviceHandle* dev_handle, uint8_t endpo s32 PS4_SYSV_ABI sceUsbdResetDevice(SceUsbdDeviceHandle* dev_handle) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_reset_device(dev_handle)); + return libusb_to_orbis_error(usb_backend->ResetDevice(dev_handle)); } s32 PS4_SYSV_ABI sceUsbdKernelDriverActive(SceUsbdDeviceHandle* dev_handle, int interface_number) { LOG_DEBUG(Lib_Usbd, "called"); -#if defined(_WIN32) - if (!s_has_removed_driver) - return 1; - else - return 0; -#endif - - return libusb_to_orbis_error(libusb_kernel_driver_active(dev_handle, interface_number)); + return libusb_to_orbis_error(usb_backend->KernelDriverActive(dev_handle, interface_number)); } s32 PS4_SYSV_ABI sceUsbdDetachKernelDriver(SceUsbdDeviceHandle* dev_handle, int interface_number) { LOG_DEBUG(Lib_Usbd, "called"); -#if defined(_WIN32) - s_has_removed_driver = true; - return 0; -#endif - - return libusb_to_orbis_error(libusb_detach_kernel_driver(dev_handle, interface_number)); + return libusb_to_orbis_error(usb_backend->DetachKernelDriver(dev_handle, interface_number)); } s32 PS4_SYSV_ABI sceUsbdAttachKernelDriver(SceUsbdDeviceHandle* dev_handle, int interface_number) { LOG_DEBUG(Lib_Usbd, "called"); -#if defined(_WIN32) - s_has_removed_driver = false; - return 0; -#endif - - return libusb_to_orbis_error(libusb_attach_kernel_driver(dev_handle, interface_number)); + return libusb_to_orbis_error(usb_backend->AttachKernelDriver(dev_handle, interface_number)); } u8* PS4_SYSV_ABI sceUsbdControlTransferGetData(SceUsbdTransfer* transfer) { @@ -264,7 +248,7 @@ SceUsbdTransfer* PS4_SYSV_ABI sceUsbdAllocTransfer(int iso_packets) { s32 PS4_SYSV_ABI sceUsbdSubmitTransfer(SceUsbdTransfer* transfer) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_submit_transfer(transfer)); + return libusb_to_orbis_error(usb_backend->SubmitTransfer(transfer)); } s32 PS4_SYSV_ABI sceUsbdCancelTransfer(SceUsbdTransfer* transfer) { @@ -336,8 +320,8 @@ s32 PS4_SYSV_ABI sceUsbdControlTransfer(SceUsbdDeviceHandle* dev_handle, u8 requ u32 timeout) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_control_transfer(dev_handle, request_type, bRequest, wValue, - wIndex, data, wLength, timeout)); + return libusb_to_orbis_error(usb_backend->ControlTransfer( + dev_handle, request_type, bRequest, wValue, wIndex, data, wLength, timeout)); } s32 PS4_SYSV_ABI sceUsbdBulkTransfer(SceUsbdDeviceHandle* dev_handle, u8 endpoint, u8* data, @@ -383,79 +367,73 @@ s32 PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii(SceUsbdDeviceHandle* dev_handle s32 PS4_SYSV_ABI sceUsbdTryLockEvents() { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_try_lock_events(g_libusb_context); + return usb_backend->TryLockEvents(); } void PS4_SYSV_ABI sceUsbdLockEvents() { LOG_DEBUG(Lib_Usbd, "called"); - libusb_lock_events(g_libusb_context); + usb_backend->LockEvents(); } void PS4_SYSV_ABI sceUsbdUnlockEvents() { LOG_DEBUG(Lib_Usbd, "called"); - libusb_unlock_events(g_libusb_context); + usb_backend->UnlockEvents(); } s32 PS4_SYSV_ABI sceUsbdEventHandlingOk() { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_event_handling_ok(g_libusb_context); + return usb_backend->EventHandlingOk(); } s32 PS4_SYSV_ABI sceUsbdEventHandlerActive() { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_event_handler_active(g_libusb_context); + return usb_backend->EventHandlerActive(); } void PS4_SYSV_ABI sceUsbdLockEventWaiters() { LOG_DEBUG(Lib_Usbd, "called"); - libusb_lock_event_waiters(g_libusb_context); + usb_backend->LockEventWaiters(); } void PS4_SYSV_ABI sceUsbdUnlockEventWaiters() { LOG_DEBUG(Lib_Usbd, "called"); - libusb_unlock_event_waiters(g_libusb_context); + usb_backend->UnlockEventWaiters(); } s32 PS4_SYSV_ABI sceUsbdWaitForEvent(timeval* tv) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_wait_for_event(g_libusb_context, tv)); + return libusb_to_orbis_error(usb_backend->WaitForEvent(tv)); } s32 PS4_SYSV_ABI sceUsbdHandleEventsTimeout(timeval* tv) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_handle_events_timeout(g_libusb_context, tv)); + return libusb_to_orbis_error(usb_backend->HandleEventsTimeout(tv)); } s32 PS4_SYSV_ABI sceUsbdHandleEvents() { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_handle_events(g_libusb_context)); + return libusb_to_orbis_error(usb_backend->HandleEvents()); } s32 PS4_SYSV_ABI sceUsbdHandleEventsLocked(timeval* tv) { LOG_DEBUG(Lib_Usbd, "called"); - return libusb_to_orbis_error(libusb_handle_events_locked(g_libusb_context, tv)); + return libusb_to_orbis_error(usb_backend->HandleEventsTimeout(tv)); } s32 PS4_SYSV_ABI sceUsbdCheckConnected(SceUsbdDeviceHandle* dev_handle) { LOG_DEBUG(Lib_Usbd, "called"); - // There's no libusb version of this function. - // Simulate by querying data. - - int config; - int r = libusb_get_configuration(dev_handle, &config); - - return libusb_to_orbis_error(r); + return libusb_to_orbis_error(usb_backend->CheckConnected(dev_handle)); } int PS4_SYSV_ABI Func_65F6EF33E38FFF50() { @@ -479,6 +457,21 @@ int PS4_SYSV_ABI Func_D56B43060720B1E0() { } void RegisterLib(Core::Loader::SymbolsResolver* sym) { + switch (Config::getUsbDeviceBackend()) { + case Config::SkylandersPortal: + usb_backend = std::make_shared(); + break; + case Config::InfinityBase: + usb_backend = std::make_shared(); + break; + case Config::DimensionsToypad: + usb_backend = std::make_shared(); + break; + default: + usb_backend = std::make_shared(); + break; + } + LIB_FUNCTION("0ktE1PhzGFU", "libSceUsbd", 1, "libSceUsbd", sceUsbdAllocTransfer); LIB_FUNCTION("BKMEGvfCPyU", "libSceUsbd", 1, "libSceUsbd", sceUsbdAttachKernelDriver); LIB_FUNCTION("fotb7DzeHYw", "libSceUsbd", 1, "libSceUsbd", sceUsbdBulkTransfer); diff --git a/src/core/libraries/usbd/usbd.h b/src/core/libraries/usbd/usbd.h index 3c20bdce4..f68b87a7a 100644 --- a/src/core/libraries/usbd/usbd.h +++ b/src/core/libraries/usbd/usbd.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "usb_backend.h" extern "C" { struct libusb_device; @@ -21,6 +22,8 @@ class SymbolsResolver; namespace Libraries::Usbd { +extern std::shared_ptr usb_backend; + using SceUsbdDevice = libusb_device; using SceUsbdDeviceHandle = libusb_device_handle; using SceUsbdDeviceDescriptor = libusb_device_descriptor; @@ -29,6 +32,11 @@ using SceUsbdTransfer = libusb_transfer; using SceUsbdControlSetup = libusb_control_setup; using SceUsbdTransferCallback = void PS4_SYSV_ABI (*)(SceUsbdTransfer* transfer); +// TODO: implement emulated devices +using SkylandersPortalBackend = UsbRealBackend; +using InfinityBaseBackend = UsbRealBackend; +using DimensionsToypadBackend = UsbRealBackend; + enum class SceUsbdSpeed : u32 { UNKNOWN = 0, LOW = 1,