diff --git a/.github/BUILDING.md b/.github/BUILDING.md index d6bf878ef2..9aebdbaa62 100644 --- a/.github/BUILDING.md +++ b/.github/BUILDING.md @@ -18,6 +18,10 @@ sudo dnf install cmake libunwind-devel glfw-devel vulkan-devel gcc-c++ gcc sox-d sudo pacman -S libunwind glfw-x11 vulkan-devel sox git cmake alsa-lib nasm ``` +### The dependencies for MacOS (iOS target, rpcs3 only): + +macOS 15, Xcode 16 (with iOS workload) and Cmake 3.20+ + ## Cloning the Repo ``` @@ -34,3 +38,10 @@ For Ubuntu 24.04 you need to manually specify compiler version: ``` cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS_INIT="-march=native" -DCMAKE_CXX_COMPILER=g++-14 && cmake --build build -j$(nproc) ``` + +For iOS you need to manually specify the compiler and toolchain file: + +``` +cmake -B build -G Xcode -DCMAKE_TOOLCHAIN_FILE=ios/ios.toolchain.cmake -DPLATFORM=OS64 -DCMAKE_POLICY_VERSION_MINIMUM=3.20 +cmake --build build --config Release +``` \ No newline at end of file diff --git a/.github/workflows/rpcsx.yml b/.github/workflows/rpcsx.yml index fe84f96058..3521a3a86c 100644 --- a/.github/workflows/rpcsx.yml +++ b/.github/workflows/rpcsx.yml @@ -24,7 +24,7 @@ jobs: sudo apt update sudo apt install -y cmake build-essential libunwind-dev \ libvulkan-dev vulkan-validationlayers \ - libsox-dev g++-14 ninja-build libasound2-dev libglfw3-dev nasm libudev-dev + libsox-dev g++-14 ninja-build libasound2-dev libglfw3-dev nasm libudev-dev libusb-1.0-0-dev cmake -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_INSTALL_PREFIX=/usr cmake --build build -j$(($(nproc) + 2)) sudo cmake --build build @@ -90,6 +90,11 @@ jobs: sudo apt update sudo apt install ninja-build + - name: Install libusb + run: | + sudo apt-get update + sudo apt-get install -y libusb-1.0-0-dev + - name: Setup Android SDK uses: android-actions/setup-android@v3 diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 01f2b89380..964c09c275 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -135,7 +135,9 @@ endif() # libusb -if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + message(STATUS "Skip libusb on iOS") +elseif(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0>=1.0 ) cmake_dependent_option(USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" ON "LIBUSB_FOUND" OFF) @@ -144,7 +146,9 @@ else() cmake_dependent_option(USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" OFF "LIBUSB_FOUND" OFF) endif() -if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + message(STATUS "Skip libusb on iOS") +elseif(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") # Always use system libusb as reference implementation isn't supported add_library(usb-1.0-shared INTERFACE) target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB) @@ -168,9 +172,13 @@ else() endif() endif() - # hidapi -add_subdirectory(hidapi) +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + add_library(3rdparty_hidapi INTERFACE) +else() + add_subdirectory(hidapi) +endif() + # glslang add_library(3rdparty_glslang INTERFACE) @@ -182,8 +190,7 @@ add_subdirectory(yaml-cpp) # OpenGL - -if (NOT ANDROID AND NOT WITHOUT_OPENGL) +if (NOT ANDROID AND NOT WITHOUT_OPENGL AND NOT CMAKE_SYSTEM_NAME MATCHES "iOS") find_package(OpenGL REQUIRED OPTIONAL_COMPONENTS EGL) add_library(3rdparty_opengl INTERFACE) @@ -209,7 +216,11 @@ endif() add_subdirectory(stblib) # Cubeb -add_subdirectory(cubeb EXCLUDE_FROM_ALL) +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + add_library(3rdparty_cubeb INTERFACE) +else() + add_subdirectory(cubeb EXCLUDE_FROM_ALL) +endif() # SoundTouch add_subdirectory(SoundTouch EXCLUDE_FROM_ALL) @@ -387,9 +398,10 @@ add_subdirectory(opencv EXCLUDE_FROM_ALL) # FUSION add_subdirectory(fusion EXCLUDE_FROM_ALL) - # add nice ALIAS targets for ease of use -if(USE_SYSTEM_LIBUSB) +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + message(STATUS "Skip libusb on iOS") +elseif(USE_SYSTEM_LIBUSB) add_library(3rdparty::libusb ALIAS usb-1.0-shared) else() add_library(3rdparty::libusb ALIAS usb-1.0-static) diff --git a/3rdparty/MoltenVK/CMakeLists.txt b/3rdparty/MoltenVK/CMakeLists.txt index 59959eecd5..56db2d3bb5 100644 --- a/3rdparty/MoltenVK/CMakeLists.txt +++ b/3rdparty/MoltenVK/CMakeLists.txt @@ -1,14 +1,29 @@ +cmake_minimum_required(VERSION 3.20) project(moltenvk NONE) include(ExternalProject) -ExternalProject_Add(moltenvk - GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git - GIT_TAG 81541f6 - BUILD_IN_SOURCE 1 - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK - CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos - BUILD_COMMAND xcodebuild build -quiet -project "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVKPackaging.xcodeproj" -scheme "MoltenVK Package \(macOS only\)" -configuration "Release" -arch "${CMAKE_HOST_SYSTEM_PROCESSOR}" - COMMAND ln -f "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK/dylib/macOS/libMoltenVK.dylib" "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Build/Products/Release/dynamic/libMoltenVK.dylib" - INSTALL_COMMAND "" - BUILD_BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Build/Products/Release/dynamic/libMoltenVK.dylib" -) +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + ExternalProject_Add(moltenvk + GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git + GIT_TAG 6f892b6 + BUILD_IN_SOURCE YES + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK + CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --ios + BUILD_COMMAND xcodebuild build -quiet -project "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVKPackaging.xcodeproj" -scheme "MoltenVK Package \(iOS only\)" -configuration "Release" -arch "arm64" + COMMAND "" + INSTALL_COMMAND "" + BUILD_BYPRODUCTS "" + ) +else() + ExternalProject_Add(moltenvk + GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git + GIT_TAG 81541f6 + BUILD_IN_SOURCE 1 + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK + CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos + BUILD_COMMAND xcodebuild build -quiet -project "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVKPackaging.xcodeproj" -scheme "MoltenVK Package \(macOS only\)" -configuration "Release" -arch "${CMAKE_HOST_SYSTEM_PROCESSOR}" + COMMAND ln -f "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK/dylib/macOS/libMoltenVK.dylib" "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Build/Products/Release/dynamic/libMoltenVK.dylib" + INSTALL_COMMAND "" + BUILD_BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Build/Products/Release/dynamic/libMoltenVK.dylib" + ) +endif() diff --git a/3rdparty/asmjit/CMakeLists.txt b/3rdparty/asmjit/CMakeLists.txt index ae88ce2fe8..f4481f5c67 100644 --- a/3rdparty/asmjit/CMakeLists.txt +++ b/3rdparty/asmjit/CMakeLists.txt @@ -17,3 +17,7 @@ target_link_libraries(asmjit PRIVATE ${ASMJIT_DEPS}) set_property(TARGET asmjit PROPERTY FOLDER "3rdparty/") add_library(3rdparty::asmjit ALIAS asmjit) + +if(CMAKE_SYSTEM_NAME MATCHES "iOS") + target_compile_options(asmjit PRIVATE -DASMJIT_NO_JIT) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 6004860656..aa1a0a06d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,32 @@ option(USE_SYSTEM_OPENCV "Prefer system OpenCV instead of the builtin one" ON) option(HAS_MEMORY_BREAKPOINTS "Add support for memory breakpoints to the interpreter" OFF) option(USE_LTO "Use LTO for building" ON) +# use global cmake to build rpcs3 for iOS at the moment +if (CMAKE_SYSTEM_NAME MATCHES "iOS") + set(WITH_RPCSX off) + set(WITH_RPCS3 on) + set(USE_SYSTEM_CURL off) + set(USE_DISCORD_RPC off) + set(USE_SYSTEM_OPENCV off) + set(USE_SYSTEM_FFMPEG off) + set(USE_FAUDIO off) + set(USE_SDL2 off) + set(WITH_LLVM off) + set(BUILD_LLVM off) + set(STATIC_LINK_LLVM off) + set(DISABLE_LTO on) + set(USE_LTO off) + set(USE_OPENSL off) + set(ASMJIT_NO_SHM_OPEN on) + set(USE_SYSTEM_ZLIB off) + set(USE_LIBEVDEV off) + set(COMPILE_FFMPEG on) + set(WITHOUT_OPENGL on) + set(WITHOUT_OPENGLEW on) + set(WITHOUT_OPENAL on) + set(USE_SYSTEM_SDL off) + set(USE_SYSTEM_MVK off) +endif() if (NOT WITH_RPCS3) set(WITHOUT_OPENGL on) diff --git a/ios/ios.toolchain.cmake b/ios/ios.toolchain.cmake new file mode 100644 index 0000000000..9046fd7c18 --- /dev/null +++ b/ios/ios.toolchain.cmake @@ -0,0 +1,1176 @@ +# This file is part of the ios-cmake project. It was retrieved from +# https://github.com/leetal/ios-cmake.git, which is a fork of +# https://github.com/gerstrong/ios-cmake.git, which is a fork of +# https://github.com/cristeab/ios-cmake.git, which is a fork of +# https://code.google.com/p/ios-cmake/. Which in turn is based off of +# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which +# are included with CMake 2.8.4 +# +# The ios-cmake project is licensed under the new BSD license. +# +# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, +# Kitware, Inc., Insight Software Consortium. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# This file is based on the Platform/Darwin.cmake and +# Platform/UnixPaths.cmake files which are included with CMake 2.8.4 +# It has been altered for iOS development. +# +# Updated by Alex Stewart (alexs.mac@gmail.com) +# +# ***************************************************************************** +# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) +# under the BSD-3-Clause license +# https://github.com/leetal/ios-cmake +# ***************************************************************************** +# +# INFORMATION / HELP +# +############################################################################### +# OPTIONS # +############################################################################### +# +# PLATFORM: (default "OS64") +# OS = Build for iPhoneOS. +# OS64 = Build for arm64 iphoneOS. +# OS64COMBINED = Build for arm64 x86_64 iphoneOS + iphoneOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR = Build for x86 i386 iphoneOS Simulator. +# SIMULATOR64 = Build for x86_64 iphoneOS Simulator. +# SIMULATORARM64 = Build for arm64 iphoneOS Simulator. +# SIMULATOR64COMBINED = Build for arm64 x86_64 iphoneOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# TVOS = Build for arm64 tvOS. +# TVOSCOMBINED = Build for arm64 x86_64 tvOS + tvOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. +# SIMULATORARM64_TVOS = Build for arm64 tvOS Simulator. +# VISIONOSCOMBINED = Build for arm64 visionOS + visionOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# VISIONOS = Build for arm64 visionOS. +# SIMULATOR_VISIONOS = Build for arm64 visionOS Simulator. +# WATCHOS = Build for armv7k arm64_32 for watchOS. +# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS + watchOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. +# SIMULATORARM64_WATCHOS = Build for arm64 for watchOS Simulator. +# SIMULATOR_WATCHOSCOMBINED = Build for arm64 x86_64 for watchOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# MAC = Build for x86_64 macOS. +# MAC_ARM64 = Build for Apple Silicon macOS. +# MAC_UNIVERSAL = Combined build for x86_64 and Apple Silicon on macOS. +# MAC_CATALYST = Build for x86_64 macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_ARM64 = Build for Apple Silicon macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_UNIVERSAL = Combined build for x86_64 and Apple Silicon on Catalyst. +# +# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is +# automatically determined from PLATFORM and xcodebuild, but +# can also be manually specified (although this should not be required). +# +# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform +# being compiled for. By default, this is automatically determined from +# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should +# not be required). +# +# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 6.0 on watchOS, 13.0 on tvOS+iOS/iPadOS, 11.0 on macOS, 1.0 on visionOS +# +# NAMED_LANGUAGE_SUPPORT: +# ON (default) = Will require "enable_language(OBJC) and/or enable_language(OBJCXX)" for full OBJC|OBJCXX support +# OFF = Will embed the OBJC and OBJCXX flags into the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (legacy behavior, CMake version < 3.16) +# +# ENABLE_BITCODE: (ON|OFF) Enables or disables bitcode support. Default OFF +# +# ENABLE_ARC: (ON|OFF) Enables or disables ARC support. Default ON (ARC enabled by default) +# +# ENABLE_VISIBILITY: (ON|OFF) Enables or disables symbol visibility support. Default OFF (visibility hidden by default) +# +# ENABLE_STRICT_TRY_COMPILE: (ON|OFF) Enables or disables strict try_compile() on all Check* directives (will run linker +# to actually check if linking is possible). Default OFF (will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) +# +# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM +# OS = armv7 armv7s arm64 (if applicable) +# OS64 = arm64 (if applicable) +# SIMULATOR = i386 +# SIMULATOR64 = x86_64 +# SIMULATORARM64 = arm64 +# TVOS = arm64 +# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_TVOS = arm64 +# WATCHOS = armv7k arm64_32 (if applicable) +# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_WATCHOS = arm64 +# MAC = x86_64 +# MAC_ARM64 = arm64 +# MAC_UNIVERSAL = x86_64 arm64 +# MAC_CATALYST = x86_64 +# MAC_CATALYST_ARM64 = arm64 +# MAC_CATALYST_UNIVERSAL = x86_64 arm64 +# +# NOTE: When manually specifying ARCHS, put a semi-colon between the entries. E.g., -DARCHS="armv7;arm64" +# +############################################################################### +# END OPTIONS # +############################################################################### +# +# This toolchain defines the following properties (available via get_property()) for use externally: +# +# PLATFORM: The currently targeted platform. +# XCODE_VERSION: Version number (not including Build version) of Xcode detected. +# SDK_VERSION: Version of SDK being used. +# OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). +# APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" is overridden, this will *NOT* be set! +# +# This toolchain defines the following macros for use externally: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) +# A convenience macro for setting xcode specific properties on targets. +# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the +# environment. Thanks to the android-cmake project for providing the +# command. +# + +cmake_minimum_required(VERSION 3.8.0) + +# CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. +# NOTE: To improve single-library build-times, provide the flag "OS_SINGLE_BUILD" as a build argument. +if(DEFINED OS_SINGLE_BUILD AND DEFINED ENV{_IOS_TOOLCHAIN_HAS_RUN}) + return() +endif() +set(ENV{_IOS_TOOLCHAIN_HAS_RUN} true) + +# List of supported platform values +list(APPEND _supported_platforms + "OS" "OS64" "OS64COMBINED" "SIMULATOR" "SIMULATOR64" "SIMULATORARM64" "SIMULATOR64COMBINED" + "TVOS" "TVOSCOMBINED" "SIMULATOR_TVOS" "SIMULATORARM64_TVOS" + "WATCHOS" "WATCHOSCOMBINED" "SIMULATOR_WATCHOS" "SIMULATORARM64_WATCHOS" "SIMULATOR_WATCHOSCOMBINED" + "MAC" "MAC_ARM64" "MAC_UNIVERSAL" + "VISIONOS" "SIMULATOR_VISIONOS" "VISIONOSCOMBINED" + "MAC_CATALYST" "MAC_CATALYST_ARM64" "MAC_CATALYST_UNIVERSAL") + +# Cache what generator is used +set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}") + +# Check if using a CMake version capable of building combined FAT builds (simulator and target slices combined in one static lib) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") + set(MODERN_CMAKE YES) +endif() + +# Get the Xcode version being used. +# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs. +# Workaround: On the first run (in which cache variables are always accessible), set an intermediary environment variable. +# +# NOTE: This pattern is used in many places in this toolchain to speed up checks of all sorts +if(DEFINED XCODE_VERSION_INT) + # Environment variables are always preserved. + set(ENV{_XCODE_VERSION_INT} "${XCODE_VERSION_INT}") +elseif(DEFINED ENV{_XCODE_VERSION_INT}) + set(XCODE_VERSION_INT "$ENV{_XCODE_VERSION_INT}") +elseif(NOT DEFINED XCODE_VERSION_INT) + find_program(XCODEBUILD_EXECUTABLE xcodebuild) + if(NOT XCODEBUILD_EXECUTABLE) + message(FATAL_ERROR "xcodebuild not found. Please install either the standalone commandline tools or Xcode.") + endif() + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version + OUTPUT_VARIABLE XCODE_VERSION_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + set(XCODE_VERSION_INT "${XCODE_VERSION_INT}" CACHE INTERNAL "") +endif() + +# Assuming that xcode 12.0 is installed you most probably have ios sdk 14.0 or later installed (tested on Big Sur) +# if you don't set a deployment target it will be set the way you only get 64-bit builds +#if(NOT DEFINED DEPLOYMENT_TARGET AND XCODE_VERSION_INT VERSION_GREATER 12.0) +# Temporarily fix the arm64 issues in CMake install-combined by excluding arm64 for simulator builds (needed for Apple Silicon...) +# set(CMAKE_XCODE_ATTRIBUTE_EXCLUDED_ARCHS[sdk=iphonesimulator*] "arm64") +#endif() + +# Check if the platform variable is set +if(DEFINED PLATFORM) + # Environment variables are always preserved. + set(ENV{_PLATFORM} "${PLATFORM}") +elseif(DEFINED ENV{_PLATFORM}) + set(PLATFORM "$ENV{_PLATFORM}") +elseif(NOT DEFINED PLATFORM) + message(FATAL_ERROR "PLATFORM argument not set. Bailing configure since I don't know what target you want to build for!") +endif () + +if(PLATFORM MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The combined builds support requires Xcode to be used as a generator via '-G Xcode' command-line argument in CMake") +endif() + +# Safeguard that the platform value is set and is one of the supported values +list(FIND _supported_platforms ${PLATFORM} contains_PLATFORM) +if("${contains_PLATFORM}" EQUAL "-1") + string(REPLACE ";" "\n * " _supported_platforms_formatted "${_supported_platforms}") + message(FATAL_ERROR " Invalid PLATFORM specified! Current value: ${PLATFORM}.\n" + " Supported PLATFORM values: \n * ${_supported_platforms_formatted}") +endif() + +# Check if Apple Silicon is supported +if(PLATFORM MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$|^(MAC_UNIVERSAL)$|^(MAC_CATALYST_UNIVERSAL)$" AND ${CMAKE_VERSION} VERSION_LESS "3.19.5") + message(FATAL_ERROR "Apple Silicon builds requires a minimum of CMake 3.19.5") +endif() + +# Touch the toolchain variable to suppress the "unused variable" warning. +# This happens if CMake is invoked with the same command line the second time. +if(CMAKE_TOOLCHAIN_FILE) +endif() + +# Fix for PThread library not in path +set(CMAKE_THREAD_LIBS_INIT "-lpthread") +set(CMAKE_HAVE_THREADS_LIBRARY 1) +set(CMAKE_USE_WIN32_THREADS_INIT 0) +set(CMAKE_USE_PTHREADS_INIT 1) + +# Specify named language support defaults. +if(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") + set(NAMED_LANGUAGE_SUPPORT ON) + message(STATUS "[DEFAULTS] Using explicit named language support! E.g., enable_language(CXX) is needed in the project files.") +elseif(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + set(NAMED_LANGUAGE_SUPPORT OFF) + message(STATUS "[DEFAULTS] Disabling explicit named language support. Falling back to legacy behavior.") +elseif(DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + message(FATAL_ERROR "CMake named language support for OBJC and OBJCXX was added in CMake 3.16.") +endif() +set(NAMED_LANGUAGE_SUPPORT_INT ${NAMED_LANGUAGE_SUPPORT} CACHE BOOL + "Whether or not to enable explicit named language support" FORCE) + +# Specify the minimum version of the deployment target. +if(NOT DEFINED DEPLOYMENT_TARGET) + if (PLATFORM MATCHES "WATCHOS") + # Unless specified, SDK version 4.0 is used by default as minimum target version (watchOS). + set(DEPLOYMENT_TARGET "6.0") + elseif(PLATFORM STREQUAL "MAC") + # Unless specified, SDK version 10.13 (High Sierra) is used by default as the minimum target version (macos). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") + # Unless specified, SDK version 1.0 is used by default as minimum target version (visionOS). + set(DEPLOYMENT_TARGET "1.0") + elseif(PLATFORM STREQUAL "MAC_ARM64") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on arm). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_UNIVERSAL") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as minimum target version for universal builds. + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") + # Unless specified, SDK version 13.0 is used by default as the minimum target version (mac catalyst minimum requirement). + set(DEPLOYMENT_TARGET "13.1") + else() + # Unless specified, SDK version 11.0 is used by default as the minimum target version (iOS, tvOS). + set(DEPLOYMENT_TARGET "13.0") + endif() + message(STATUS "[DEFAULTS] Using the default min-version since DEPLOYMENT_TARGET not provided!") +elseif(DEFINED DEPLOYMENT_TARGET AND PLATFORM MATCHES "^MAC_CATALYST" AND ${DEPLOYMENT_TARGET} VERSION_LESS "13.1") + message(FATAL_ERROR "Mac Catalyst builds requires a minimum deployment target of 13.1!") +endif() + +# Store the DEPLOYMENT_TARGET in the cache +set(DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}" CACHE INTERNAL "") + +# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) +if(PLATFORM STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "OS64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +elseif(PLATFORM STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "SIMULATOR64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +endif() + +set(PLATFORM_INT "${PLATFORM}") + +if(DEFINED ARCHS) + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") +endif() + +# Determine the platform name and architectures for use in xcodebuild commands +# from the specified PLATFORM_INT name. +if(PLATFORM_INT STREQUAL "OS") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + set(ARCHS armv7 armv7s arm64) + set(APPLE_TARGET_TRIPLE_INT arm-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS arm64) # FIXME: Add arm64e when Apple has fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + else() + set(ARCHS arm64) + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64COMBINED") + set(SDK_NAME iphoneos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR64COMBINED") + set(SDK_NAME iphonesimulator) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) # FIXME: Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") +elseif(PLATFORM_INT STREQUAL "SIMULATOR64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME appletvos) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() +elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") + set(SDK_NAME appletvos) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64 x86_64) + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-tvos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME watchos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32) + set(APPLE_TARGET_TRIPLE_INT arm64_32-apple-watchos${DEPLOYMENT_TARGET}) + else() + set(ARCHS armv7k) + set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") + set(SDK_NAME watchos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32 x86_64) + set(APPLE_TARGET_TRIPLE_INT arm64_32-x86_64-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "x86_64") + else() + set(ARCHS armv7k i386) + set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOSCOMBINED") + set(SDK_NAME watchsimulator) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "arm64 x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "arm64 x86_64") + set(APPLE_TARGET_TRIPLE_INT arm64_x86_64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(ARCHS arm64 i386) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + set(APPLE_TARGET_TRIPLE_INT arm64_i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR_WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_VISIONOS") + set(SDK_NAME xrsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "VISIONOS") + set(SDK_NAME xros) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "VISIONOSCOMBINED") + set(SDK_NAME xros) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xros*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xrsimulator*] "arm64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the VISIONOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "MAC" OR PLATFORM_INT STREQUAL "MAC_CATALYST") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS x86_64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS arm64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT STREQUAL "MAC_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) +elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) +else() + message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") +endif() + +string(REPLACE ";" " " ARCHS_SPACED "${ARCHS}") + +if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") +endif() + +if(CMAKE_GENERATOR MATCHES "Xcode" AND PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES") + if(NOT DEFINED MACOSX_DEPLOYMENT_TARGET) + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.15") + else() + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "${MACOSX_DEPLOYMENT_TARGET}") + endif() +elseif(CMAKE_GENERATOR MATCHES "Xcode") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}") + if(NOT PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + endif() +endif() + +# If the user did not specify the SDK root to use, then query xcodebuild for it. +if(DEFINED CMAKE_OSX_SYSROOT_INT) + # Environment variables are always preserved. + set(ENV{_CMAKE_OSX_SYSROOT_INT} "${CMAKE_OSX_SYSROOT_INT}") +elseif(DEFINED ENV{_CMAKE_OSX_SYSROOT_INT}) + set(CMAKE_OSX_SYSROOT_INT "$ENV{_CMAKE_OSX_SYSROOT_INT}") +elseif(NOT DEFINED CMAKE_OSX_SYSROOT_INT) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version -sdk ${SDK_NAME} Path + OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) + message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" + "is pointing to the correct path. Please run:" + "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" + "and see if that fixes the problem for you.") + message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " + "does not exist.") +elseif(DEFINED CMAKE_OSX_SYSROOT_INT) + set(CMAKE_OSX_SYSROOT_INT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + # Specify the location or name of the platform SDK to be used in CMAKE_OSX_SYSROOT. + set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") +endif() + +# Use bitcode or not +if(NOT DEFINED ENABLE_BITCODE) + message(STATUS "[DEFAULTS] Disabling bitcode support by default. ENABLE_BITCODE not provided for override!") + set(ENABLE_BITCODE OFF) +endif() +set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL + "Whether or not to enable bitcode" FORCE) +# Use ARC or not +if(NOT DEFINED ENABLE_ARC) + # Unless specified, enable ARC support by default + set(ENABLE_ARC ON) + message(STATUS "[DEFAULTS] Enabling ARC support by default. ENABLE_ARC not provided!") +endif() +set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" FORCE) +# Use hidden visibility or not +if(NOT DEFINED ENABLE_VISIBILITY) + # Unless specified, disable symbols visibility by default + set(ENABLE_VISIBILITY OFF) + message(STATUS "[DEFAULTS] Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") +endif() +set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols from the dynamic linker (-fvisibility=hidden)" FORCE) +# Set strict compiler checks or not +if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) + # Unless specified, disable strict try_compile() + set(ENABLE_STRICT_TRY_COMPILE OFF) + message(STATUS "[DEFAULTS] Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") +endif() +set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL + "Whether or not to use strict compiler checks" FORCE) + +# Get the SDK version information. +if(DEFINED SDK_VERSION) + # Environment variables are always preserved. + set(ENV{_SDK_VERSION} "${SDK_VERSION}") +elseif(DEFINED ENV{_SDK_VERSION}) + set(SDK_VERSION "$ENV{_SDK_VERSION}") +elseif(NOT DEFINED SDK_VERSION) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -sdk ${CMAKE_OSX_SYSROOT_INT} -version SDKVersion + OUTPUT_VARIABLE SDK_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Find the Developer root for the specific iOS platform being compiled for +# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in +# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain +# this information from xcrun or xcodebuild. +if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT CMAKE_GENERATOR MATCHES "Xcode") + get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT_INT} PATH) + get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) + if (NOT EXISTS "${CMAKE_DEVELOPER_ROOT}") + message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: ${CMAKE_DEVELOPER_ROOT} does not exist.") + endif() +endif() + +# Find the C & C++ compilers for the specified SDK. +if(DEFINED CMAKE_C_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_C_COMPILER} "${CMAKE_C_COMPILER}") +elseif(DEFINED ENV{_CMAKE_C_COMPILER}) + set(CMAKE_C_COMPILER "$ENV{_CMAKE_C_COMPILER}") + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +elseif(NOT DEFINED CMAKE_C_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang + OUTPUT_VARIABLE CMAKE_C_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +endif() +if(DEFINED CMAKE_CXX_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") +elseif(DEFINED ENV{_CMAKE_CXX_COMPILER}) + set(CMAKE_CXX_COMPILER "$ENV{_CMAKE_CXX_COMPILER}") +elseif(NOT DEFINED CMAKE_CXX_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang++ + OUTPUT_VARIABLE CMAKE_CXX_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find (Apple's) libtool. +if(DEFINED BUILD_LIBTOOL) + # Environment variables are always preserved. + set(ENV{_BUILD_LIBTOOL} "${BUILD_LIBTOOL}") +elseif(DEFINED ENV{_BUILD_LIBTOOL}) + set(BUILD_LIBTOOL "$ENV{_BUILD_LIBTOOL}") +elseif(NOT DEFINED BUILD_LIBTOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find libtool + OUTPUT_VARIABLE BUILD_LIBTOOL + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find the toolchain's provided install_name_tool if none is found on the host +if(DEFINED CMAKE_INSTALL_NAME_TOOL) + # Environment variables are always preserved. + set(ENV{_CMAKE_INSTALL_NAME_TOOL} "${CMAKE_INSTALL_NAME_TOOL}") +elseif(DEFINED ENV{_CMAKE_INSTALL_NAME_TOOL}) + set(CMAKE_INSTALL_NAME_TOOL "$ENV{_CMAKE_INSTALL_NAME_TOOL}") +elseif(NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find install_name_tool + OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE INTERNAL "") +endif() + +# Configure libtool to be used instead of ar + ranlib to build static libraries. +# This is required on Xcode 7+, but should also work on previous versions of +# Xcode. +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${languages}) + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o " CACHE INTERNAL "") +endforeach() + +# CMake 3.14+ support building for iOS, watchOS, and tvOS out of the box. +if(MODERN_CMAKE) + if(SDK_NAME MATCHES "iphone") + set(CMAKE_SYSTEM_NAME iOS) + elseif(SDK_NAME MATCHES "xros") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "xrsimulator") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "macosx") + set(CMAKE_SYSTEM_NAME Darwin) + elseif(SDK_NAME MATCHES "appletv") + set(CMAKE_SYSTEM_NAME tvOS) + elseif(SDK_NAME MATCHES "watch") + set(CMAKE_SYSTEM_NAME watchOS) + endif() + # Provide flags for a combined FAT library build on newer CMake versions + if(PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_IOS_INSTALL_COMBINED YES) + if(CMAKE_GENERATOR MATCHES "Xcode") + # Set the SDKROOT Xcode properties to a Xcode-friendly value (the SDK_NAME, E.g, iphoneos) + # This way, Xcode will automatically switch between the simulator and device SDK when building. + set(CMAKE_XCODE_ATTRIBUTE_SDKROOT "${SDK_NAME}") + # Force to not build just one ARCH, but all! + set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") + endif() + endif() +elseif(NOT DEFINED CMAKE_SYSTEM_NAME AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") + # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME iOS) +elseif(NOT DEFINED CMAKE_SYSTEM_NAME) + # Legacy code path before CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME Darwin) +endif() +# Standard settings. +set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") +set(UNIX ON CACHE BOOL "") +set(APPLE ON CACHE BOOL "") +if(PLATFORM STREQUAL "MAC" OR PLATFORM STREQUAL "MAC_ARM64" OR PLATFORM STREQUAL "MAC_UNIVERSAL") + set(IOS OFF CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") + set(IOS ON CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") + set(IOS OFF CACHE BOOL "") + set(VISIONOS ON CACHE BOOL "") +else() + set(IOS ON CACHE BOOL "") +endif() +# Set the architectures for which to build. +set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE INTERNAL "") +# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks +if(NOT ENABLE_STRICT_TRY_COMPILE_INT) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() +# All iOS/Darwin specific settings - some may be redundant. +if (NOT DEFINED CMAKE_MACOSX_BUNDLE) + set(CMAKE_MACOSX_BUNDLE YES) +endif() +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO") +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so") +set(CMAKE_SHARED_MODULE_PREFIX "lib") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") +set(CMAKE_C_COMPILER_ABI ELF) +set(CMAKE_CXX_COMPILER_ABI ELF) +set(CMAKE_C_HAS_ISYSROOT 1) +set(CMAKE_CXX_HAS_ISYSROOT 1) +set(CMAKE_MODULE_EXISTS 1) +set(CMAKE_DL_LIBS "") +set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") + set(CMAKE_C_SIZEOF_DATA_PTR 8) + set(CMAKE_CXX_SIZEOF_DATA_PTR 8) + if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") + else() + set(CMAKE_SYSTEM_PROCESSOR "x86_64") + endif() +else() + set(CMAKE_C_SIZEOF_DATA_PTR 4) + set(CMAKE_CXX_SIZEOF_DATA_PTR 4) + set(CMAKE_SYSTEM_PROCESSOR "arm") +endif() + +# Note that only Xcode 7+ supports the newer more specific: +# -m${SDK_NAME}-version-min flags, older versions of Xcode use: +# -m(ios/ios-simulator)-version-min instead. +if(${CMAKE_VERSION} VERSION_LESS "3.11") + if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") + if(XCODE_VERSION_INT VERSION_LESS 7.0) + set(SDK_NAME_VERSION_FLAGS + "-mios-version-min=${DEPLOYMENT_TARGET}") + else() + # Xcode 7.0+ uses flags we can build directly from SDK_NAME. + set(SDK_NAME_VERSION_FLAGS + "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") + endif() + elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "MAC") + set(SDK_NAME_VERSION_FLAGS + "-mmacosx-version-min=${DEPLOYMENT_TARGET}") + else() + # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. + set(SDK_NAME_VERSION_FLAGS + "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") + endif() +elseif(NOT PLATFORM_INT MATCHES "^MAC_CATALYST") + # Newer versions of CMake sets the version min flags correctly, skip this for Mac Catalyst targets + set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE INTERNAL "Minimum OS X deployment version") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE_INT) + set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE INTERNAL "") + set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_CXX_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) +endif() + +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(C_TARGET_FLAGS "-isystem ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/usr/include -iframework ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks") +endif() + +if(ENABLE_BITCODE_INT) + set(BITCODE "-fembed-bitcode") + set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") +else() + set(BITCODE "") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") +endif() + +if(ENABLE_ARC_INT) + set(FOBJC_ARC "-fobjc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") +else() + set(FOBJC_ARC "-fno-objc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO") +endif() + +if(NAMED_LANGUAGE_SUPPORT_INT) + set(OBJC_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") + set(OBJC_LEGACY_VARS "") +else() + set(OBJC_VARS "") + set(OBJC_LEGACY_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") +endif() + +if(NOT ENABLE_VISIBILITY_INT) + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "hidden" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES") + set(VISIBILITY "-fvisibility=hidden -fvisibility-inlines-hidden") +else() + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "default" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO") + set(VISIBILITY "-fvisibility=default") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE) + set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") +endif() + +#Check if Xcode generator is used since that will handle these flags automagically +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as the generator. Modifying the Xcode build-settings directly instead.") +else() + set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_C_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all C build types.") + set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_C_FLAGS_MINSIZEREL}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_CXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all CXX build types.") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_CXX_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_CXX_FLAGS_RELEASE}") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJC_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJC build types.") + set(CMAKE_OBJC_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJC_FLAGS_DEBUG}") + set(CMAKE_OBJC_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJC_FLAGS_MINSIZEREL}") + set(CMAKE_OBJC_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJC_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJC_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJC_FLAGS_RELEASE}") + set(CMAKE_OBJCXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJCXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJCXX build types.") + set(CMAKE_OBJCXX_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJCXX_FLAGS_DEBUG}") + set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJCXX_FLAGS_MINSIZEREL}") + set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJCXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJCXX_FLAGS_RELEASE}") + endif() + set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all C link types.") + set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all CXX link types.") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJC_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJC link types.") + set(CMAKE_OBJCXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJCXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJCXX link types.") + endif() + set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -arch ${CMAKE_OSX_ARCHITECTURES} ${APPLE_TARGET_TRIPLE_FLAG}" CACHE INTERNAL + "Flags used by the compiler for all ASM build types.") +endif() + +## Print status messages to inform of the current state +message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") +message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") +message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") +message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Using libtool: ${BUILD_LIBTOOL}") +message(STATUS "Using install name tool: ${CMAKE_INSTALL_NAME_TOOL}") +if(DEFINED APPLE_TARGET_TRIPLE) + message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") +endif() +message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" + " (SDK version: ${SDK_VERSION})") +if(MODERN_CMAKE) + message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") + if(PLATFORM_INT MATCHES ".*COMBINED") + message(STATUS "Will combine built (static) artifacts into FAT lib...") + endif() +endif() +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Using Xcode version: ${XCODE_VERSION_INT}") +endif() +message(STATUS "CMake version: ${CMAKE_VERSION}") +if(DEFINED SDK_NAME_VERSION_FLAGS) + message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") +endif() +message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") +if(ENABLE_BITCODE_INT) + message(STATUS "Bitcode: Enabled") +else() + message(STATUS "Bitcode: Disabled") +endif() + +if(ENABLE_ARC_INT) + message(STATUS "ARC: Enabled") +else() + message(STATUS "ARC: Disabled") +endif() + +if(ENABLE_VISIBILITY_INT) + message(STATUS "Hiding symbols: Disabled") +else() + message(STATUS "Hiding symbols: Enabled") +endif() + +# Set global properties +set_property(GLOBAL PROPERTY PLATFORM "${PLATFORM}") +set_property(GLOBAL PROPERTY APPLE_TARGET_TRIPLE "${APPLE_TARGET_TRIPLE_INT}") +set_property(GLOBAL PROPERTY SDK_VERSION "${SDK_VERSION}") +set_property(GLOBAL PROPERTY XCODE_VERSION "${XCODE_VERSION_INT}") +set_property(GLOBAL PROPERTY OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + +# Export configurable variables for the try_compile() command. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + PLATFORM + XCODE_VERSION_INT + SDK_VERSION + NAMED_LANGUAGE_SUPPORT + DEPLOYMENT_TARGET + CMAKE_DEVELOPER_ROOT + CMAKE_OSX_SYSROOT_INT + ENABLE_BITCODE + ENABLE_ARC + CMAKE_ASM_COMPILER + CMAKE_C_COMPILER + CMAKE_C_COMPILER_TARGET + CMAKE_CXX_COMPILER + CMAKE_CXX_COMPILER_TARGET + BUILD_LIBTOOL + CMAKE_INSTALL_NAME_TOOL + CMAKE_C_FLAGS + CMAKE_C_DEBUG + CMAKE_C_MINSIZEREL + CMAKE_C_RELWITHDEBINFO + CMAKE_C_RELEASE + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_LINK_FLAGS + CMAKE_CXX_LINK_FLAGS + CMAKE_ASM_FLAGS +) + +if(NAMED_LANGUAGE_SUPPORT_INT) + list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_OBJC_FLAGS + CMAKE_OBJC_DEBUG + CMAKE_OBJC_MINSIZEREL + CMAKE_OBJC_RELWITHDEBINFO + CMAKE_OBJC_RELEASE + CMAKE_OBJCXX_FLAGS + CMAKE_OBJCXX_DEBUG + CMAKE_OBJCXX_MINSIZEREL + CMAKE_OBJCXX_RELWITHDEBINFO + CMAKE_OBJCXX_RELEASE + CMAKE_OBJC_LINK_FLAGS + CMAKE_OBJCXX_LINK_FLAGS + ) +endif() + +set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") + +# Set the find root to the SDK developer roots. +# Note: CMAKE_FIND_ROOT_PATH is only useful when cross-compiling. Thus, do not set on macOS builds. +if(NOT PLATFORM_INT MATCHES "^MAC.*$") + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + set(CMAKE_IGNORE_PATH "/System/Library/Frameworks;/usr/local/lib;/opt/homebrew" CACHE INTERNAL "") +endif() + +# Default to searching for frameworks first. +IF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + set(CMAKE_FIND_FRAMEWORK FIRST) +ENDIF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + +# Set up the default search directories for frameworks. +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +else() + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +endif() + +# By default, search both the specified iOS SDK and the remainder of the host filesystem. +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") +endif() + +# +# Some helper-macros below to simplify and beautify the CMakeFile +# + +# This little macro lets you set any Xcode specific property. +macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) + set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") + if(XCODE_RELVERSION_I STREQUAL "All") + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") + else() + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") + endif() +endmacro(set_xcode_property) + +# This macro lets you find executable programs on the host system. +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) + set(_TOOLCHAIN_IOS ${IOS}) + set(IOS OFF) + find_package(${ARGN}) + set(IOS ${_TOOLCHAIN_IOS}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) +endmacro(find_host_package) diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 43990629e6..0fb9662af9 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -170,7 +170,6 @@ target_link_libraries(rpcs3 PUBLIC 3rdparty::pugixml 3rdparty::discordRPC 3rdparty::hidapi - 3rdparty::libusb 3rdparty::libpng 3rdparty::7zip 3rdparty::wolfssl @@ -185,6 +184,10 @@ target_link_libraries(rpcs3 PUBLIC ${ADDITIONAL_LIBS} ) +if (NOT CMAKE_SYSTEM_NAME MATCHES "iOS") + target_link_libraries(rpcs3 PUBLIC 3rdparty::libusb) +endif() + if(USE_PRECOMPILED_HEADERS) target_precompile_headers(rpcs3 PUBLIC stdafx.h) endif() @@ -196,3 +199,7 @@ elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE AND NOT ANDROID) # Wayland has been checked in 3rdparty/CMakeLists.txt already. message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.") endif() + +if(CMAKE_SYSTEM_NAME MATCHES "iOS") + target_compile_options(rpcs3 PRIVATE -D_LIBCPP_DISABLE_AVAILABILITY -DWITHOUT_CUBEB -DWITHOUT_HIDAPI) +endif() diff --git a/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp b/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp index 4d3ad33d67..1ff1ca4099 100644 --- a/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp +++ b/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_CUBEB + #include "Emu/Audio/Cubeb/CubebBackend.h" #include @@ -593,3 +595,5 @@ void CubebBackend::log_cb(const char* fmt, ...) Cubeb.notice("Cubeb log: %s", buf); } + +#endif // WITHOUT_CUBEB diff --git a/rpcs3/Emu/Audio/Cubeb/CubebBackend.h b/rpcs3/Emu/Audio/Cubeb/CubebBackend.h index cf3a978250..cc3b8f7109 100644 --- a/rpcs3/Emu/Audio/Cubeb/CubebBackend.h +++ b/rpcs3/Emu/Audio/Cubeb/CubebBackend.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_CUBEB #include "util/atomic.hpp" #include "Emu/Audio/AudioBackend.h" @@ -66,3 +67,5 @@ class CubebBackend final : public AudioBackend device_handle GetDevice(std::string_view dev_id = ""); device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 ch_cnt); }; + +#endif // WITHOUT_CUBEB diff --git a/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.cpp b/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.cpp index 442a091b9c..faa502e0d1 100644 --- a/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.cpp +++ b/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_CUBEB + #include "Emu/Audio/Cubeb/cubeb_enumerator.h" #include "util/logs.hpp" #include @@ -112,3 +114,5 @@ std::vector cubeb_enumerator::get_output_ return device_list; } + +#endif // WITHOUT_CUBEB diff --git a/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.h b/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.h index eb5b1cb839..331ff3f226 100644 --- a/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.h +++ b/rpcs3/Emu/Audio/Cubeb/cubeb_enumerator.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_CUBEB #include "Emu/Audio/audio_device_enumerator.h" @@ -18,3 +19,5 @@ class cubeb_enumerator final : public audio_device_enumerator bool com_init_success = false; #endif }; + +#endif // WITHOUT_CUBEB diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index bfcf682a21..7eb38ccb80 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -99,7 +99,6 @@ endif() target_link_libraries(rpcs3_emu PUBLIC 3rdparty::openal - 3rdparty::cubeb 3rdparty::soundtouch 3rdparty::miniupnpc 3rdparty::json @@ -196,7 +195,7 @@ target_sources(rpcs3_emu PRIVATE CPU/CPUTranslator.cpp ) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64" AND NOT CMAKE_SYSTEM_NAME MATCHES "iOS") target_sources(rpcs3_emu PRIVATE CPU/Backends/AArch64/AArch64ASM.cpp CPU/Backends/AArch64/AArch64Common.cpp @@ -206,39 +205,25 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64") endif() target_link_libraries(rpcs3_emu - PUBLIC 3rdparty::llvm 3rdparty::asmjit) + PUBLIC 3rdparty::llvm 3rdparty::asmjit) +if(NOT CMAKE_SYSTEM_NAME MATCHES "iOS") + target_link_libraries(rpcs3_emu + PUBLIC 3rdparty::cubeb) +endif() # Io target_sources(rpcs3_emu PRIVATE - Io/Buzz.cpp Io/camera_config.cpp - Io/Dimensions.cpp - Io/GameTablet.cpp - Io/GHLtar.cpp - Io/GunCon3.cpp - Io/Infinity.cpp Io/interception.cpp Io/KeyboardHandler.cpp - Io/midi_config_types.cpp Io/mouse_config.cpp Io/MouseHandler.cpp Io/pad_config.cpp Io/pad_config_types.cpp Io/pad_types.cpp Io/PadHandler.cpp - Io/rb3drums_config.cpp - Io/RB3MidiDrums.cpp - Io/RB3MidiGuitar.cpp - Io/RB3MidiKeyboard.cpp Io/recording_config.cpp - Io/Skylander.cpp - Io/TopShotElite.cpp - Io/TopShotFearmaster.cpp - Io/Turntable.cpp - Io/usb_device.cpp - Io/usb_vfs.cpp - Io/usio.cpp ) target_link_libraries(rpcs3_emu PRIVATE @@ -355,7 +340,7 @@ target_sources(rpcs3_emu PRIVATE RSX/rsx_vertex_data.cpp ) -if(NOT ANDROID) +if(NOT ANDROID AND NOT CMAKE_SYSTEM_NAME MATCHES "iOS") target_sources(rpcs3_emu PRIVATE RSX/GL/GLCommonDecompiler.cpp RSX/GL/GLCompute.cpp @@ -442,7 +427,7 @@ target_link_libraries(rpcs3_emu 3rdparty::ffmpeg 3rdparty::sdl3 3rdparty::opengl 3rdparty::stblib 3rdparty::vulkan 3rdparty::glew - 3rdparty::libusb 3rdparty::wolfssl + 3rdparty::wolfssl Vulkan::Headers rpcsx::fw::ps3::api @@ -450,6 +435,10 @@ target_link_libraries(rpcs3_emu 3rdparty::glslang ) +if (NOT CMAKE_SYSTEM_NAME MATCHES "iOS") + target_link_libraries(rpcs3_emu PUBLIC 3rdparty::libusb) +endif() + if(APPLE) check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) if (HAVE_CLOCK_GETTIME) @@ -461,3 +450,7 @@ endif() if(USE_PRECOMPILED_HEADERS) target_precompile_headers(rpcs3_emu PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h") endif() + +if(CMAKE_SYSTEM_NAME MATCHES "iOS") + target_compile_options(rpcs3_emu PRIVATE -D_LIBCPP_DISABLE_AVAILABILITY -DWITHOUT_CUBEB -DWITHOUT_HIDAPI) +endif() diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index bb3e7bb8d0..62b763e29b 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -69,6 +69,7 @@ #ifdef __APPLE__ #include +#include #endif extern atomic_t g_watchdog_hold_ctr; @@ -2238,7 +2239,7 @@ void ppu_thread::cpu_task() } case ppu_cmd::lle_call: { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif const vm::ptr opd(arg < 32 ? vm::cast(gpr[arg]) : vm::cast(arg)); @@ -2247,7 +2248,7 @@ void ppu_thread::cpu_task() } case ppu_cmd::entry_call: { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif cmd_pop(), fast_call(entry_func.addr, entry_func.rtoc, true); @@ -2260,7 +2261,7 @@ void ppu_thread::cpu_task() } case ppu_cmd::opd_call: { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif const ppu_func_opd_t opd = cmd_get(1).as(); @@ -2281,7 +2282,7 @@ void ppu_thread::cpu_task() } case ppu_cmd::initialize: { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif cmd_pop(); @@ -2295,7 +2296,7 @@ void ppu_thread::cpu_task() spu_cache::initialize(); -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif #ifdef ARCH_ARM64 @@ -2519,7 +2520,7 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3 syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1); syscall_history.count_debug_arguments = static_cast(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0); -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif #ifdef ARCH_ARM64 @@ -4302,7 +4303,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector(software_thread_limit, cpu_thread_limit), [&] { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif // Set low priority @@ -4466,7 +4467,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector& info, bool check_only, u64 file_s // Try to make the code fit in 16 bytes, may fail and fallback if (*full_sample && abs_diff(*full_sample, reinterpret_cast(jit_runtime::peek(true) + 3 * 4)) < (128u << 20)) { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif u8* code = jit_runtime::alloc(12, 4, true); @@ -5533,7 +5534,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s // Set low priority thread_ctrl::scoped_priority low_prio(-1); -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif for (u32 i = work_cv++; i < workload.size(); i = work_cv++, g_progr_pdone++) @@ -5672,7 +5673,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s } // Jit can be null if the loop doesn't ever enter. -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif // Try to patch all single and unregistered BLRs with the same function (TODO: Maybe generalize it into PIC code detection and patching) @@ -5699,7 +5700,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s } } -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) // Symbol resolver is in JIT mem, so we must enable execution pthread_jit_write_protect_np(true); #endif @@ -5715,7 +5716,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s } } -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) // Symbol resolver is in JIT mem, so we must enable execution pthread_jit_write_protect_np(false); #endif diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index 74ae4055a0..dae0481774 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -29,6 +29,10 @@ #include "util/simd.hpp" #include "util/sysinfo.hpp" +#ifdef __APPLE__ +#include +#endif + const extern spu_decoder g_spu_itype; const extern spu_decoder g_spu_iname; const extern spu_decoder g_spu_iflag; @@ -106,7 +110,7 @@ static void ghc_cpp_trampoline(u64 fn_target, native_asm& c, auto& args) DECLARE(spu_runtime::tr_dispatch) = [] { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif #if defined(ARCH_X64) @@ -831,7 +835,7 @@ void spu_cache::initialize(bool build_existing_cache) named_thread_group workers("SPU Worker ", worker_count, [&]() -> uint { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif // Set low priority @@ -2005,7 +2009,7 @@ spu_function_t spu_runtime::make_branch_patchpoint(u16 data) const return reinterpret_cast(raw); #elif defined(ARCH_ARM64) -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif @@ -2046,7 +2050,7 @@ spu_function_t spu_runtime::make_branch_patchpoint(u16 data) const *raw++ = static_cast(data >> 8); *raw++ = static_cast(data & 0xff); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif @@ -2110,11 +2114,11 @@ void spu_recompiler_base::dispatch(spu_thread& spu, void*, u8* rip) const u64 target = reinterpret_cast(spu_runtime::tr_all); std::memcpy(bytes + 8, &target, 8); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif atomic_storage::release(*reinterpret_cast(rip), result); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif @@ -2160,7 +2164,7 @@ void spu_recompiler_base::dispatch(spu_thread& spu, void*, u8* rip) spu_log.trace("Called from 0x%x", _info._u32[2] - 4); } } -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif @@ -2250,11 +2254,11 @@ void spu_recompiler_base::branch(spu_thread& spu, void*, u8* rip) const u64 target = reinterpret_cast(func); std::memcpy(bytes + 8, &target, 8); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif atomic_storage::release(*reinterpret_cast(rip), result); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 27f1434dc6..53fed0bbe0 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -46,6 +46,10 @@ #endif #endif +#ifdef __APPLE__ +#include +#endif + // LUTs for SPU instructions const u32 spu_frest_fraction_lut[32] = @@ -1827,7 +1831,7 @@ extern thread_local std::string (*g_tls_log_prefix)(); void spu_thread::cpu_task() { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif start_time = 0; diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index c4e7c3643a..7f0a81d06e 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -69,6 +69,10 @@ #endif #endif +#ifdef __APPLE__ +#include +#endif + extern std::string ppu_get_syscall_name(u64 code); namespace rsx @@ -1251,13 +1255,13 @@ extern void ppu_execute_syscall(ppu_thread& ppu, u64 code) if (const auto func = g_ppu_syscall_table[code].first) { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif func(ppu, {}, vm::_ptr(ppu.cia), nullptr); ppu_log.trace("Syscall '%s' (%llu) finished, r3=0x%llx", ppu_syscall_code(code), code, ppu.gpr[3]); -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); // No need to flush cache lines after a syscall, since we didn't generate any code. #endif diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index cb0f15afa0..45333936bd 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -3,62 +3,11 @@ #include "sys_ppu_thread.h" #include "sys_sync.h" -#include -#include "Emu/System.h" -#include "Emu/system_config.h" -#include "Emu/IdManager.h" -#include "Emu/vfs_config.h" - #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/ErrorCodes.h" -#include "Emu/Cell/timers.hpp" - -#include "Emu/Io/usb_device.h" -#include "Emu/Io/usb_vfs.h" -#include "Emu/Io/Skylander.h" -#include "Emu/Io/Infinity.h" -#include "Emu/Io/Dimensions.h" -#include "Emu/Io/GHLtar.h" -#include "Emu/Io/ghltar_config.h" -#include "Emu/Io/guncon3_config.h" -#include "Emu/Io/topshotelite_config.h" -#include "Emu/Io/topshotfearmaster_config.h" -#include "Emu/Io/Buzz.h" -#include "Emu/Io/buzz_config.h" -#include "Emu/Io/GameTablet.h" -#include "Emu/Io/GunCon3.h" -#include "Emu/Io/TopShotElite.h" -#include "Emu/Io/TopShotFearmaster.h" -#include "Emu/Io/Turntable.h" -#include "Emu/Io/turntable_config.h" -#include "Emu/Io/RB3MidiKeyboard.h" -#include "Emu/Io/RB3MidiGuitar.h" -#include "Emu/Io/RB3MidiDrums.h" -#include "Emu/Io/rb3drums_config.h" -#include "Emu/Io/usio.h" -#include "Emu/Io/usio_config.h" -#include "Emu/Io/midi_config_types.h" - -#include LOG_CHANNEL(sys_usbd); -cfg_buzz g_cfg_buzz; -cfg_ghltars g_cfg_ghltar; -cfg_turntables g_cfg_turntable; -cfg_usios g_cfg_usio; -cfg_guncon3 g_cfg_guncon3; -cfg_topshotelite g_cfg_topshotelite; -cfg_topshotfearmaster g_cfg_topshotfearmaster; - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - const auto& transfer = get_object(arg); - const int data_start = transfer.type == LIBUSB_TRANSFER_TYPE_CONTROL ? LIBUSB_CONTROL_SETUP_SIZE : 0; - fmt::append(out, "TR[r:%d][sz:%d] => %s", +transfer.status, transfer.actual_length, fmt::buf_to_hexstring(&transfer.buffer[data_start], transfer.actual_length)); -} - struct UsbLdd { u16 id_vendor{}; @@ -66,988 +15,12 @@ struct UsbLdd u16 id_product_max{}; }; -struct UsbPipe -{ - std::shared_ptr device = nullptr; - - u8 endpoint = 0; -}; - -struct usb_allow_list_entry -{ - u16 id_vendor; - u16 id_product_min; - u16 id_product_max; - std::string_view device_name; - u16 (*max_device_count)(void); - std::shared_ptr (*make_instance)(u32, const std::array&); - auto operator<(const usb_allow_list_entry& r) const - { - return std::tuple(id_vendor, id_product_min, id_product_max, device_name, max_device_count, make_instance) < std::tuple(r.id_vendor, r.id_product_min, r.id_product_max, device_name, max_device_count, make_instance); - } -}; -class usb_handler_thread -{ -public: - usb_handler_thread(); - ~usb_handler_thread(); - - SAVESTATE_INIT_POS(14); - - usb_handler_thread(utils::serial& ar) : usb_handler_thread() - { - is_init = !!ar.pop(); - } - - void save(utils::serial& ar) - { - ar(u8{is_init.load()}); - } - - // Thread loop - void operator()(); - - // Called by the libusb callback function to notify transfer completion - void transfer_complete(libusb_transfer* transfer); - - // LDDs handling functions - bool add_ldd(std::string_view product, u16 id_vendor, u16 id_product_min, u16 id_product_max); - bool remove_ldd(std::string_view product); - - // Pipe functions - u32 open_pipe(u32 device_handle, u8 endpoint); - bool close_pipe(u32 pipe_id); - bool is_pipe(u32 pipe_id) const; - const UsbPipe& get_pipe(u32 pipe_id) const; - - // Events related functions - bool get_event(vm::ptr& arg1, vm::ptr& arg2, vm::ptr& arg3); - void add_event(u64 arg1, u64 arg2, u64 arg3); - - // Transfers related functions - std::pair get_free_transfer(); - std::pair get_transfer_status(u32 transfer_id); - std::pair get_isochronous_transfer_status(u32 transfer_id); - void push_fake_transfer(UsbTransfer* transfer); - - const std::array& get_new_location(); - void connect_usb_device(std::shared_ptr dev, bool update_usb_devices = false); - void disconnect_usb_device(std::shared_ptr dev, bool update_usb_devices = false); - - // Map of devices actively handled by the ps3(device_id, device) - std::map>> handled_devices; - std::map>> pad_to_usb; - - shared_mutex mutex; - atomic_t is_init = false; - - // sys_usbd_receive_event PPU Threads - shared_mutex mutex_sq; - ppu_thread* sq{}; - - atomic_t usb_hotplug_timeout = umax; - - static constexpr auto thread_name = "Usb Manager Thread"sv; - -private: - // Lock free functions for internal use(ie make sure to lock before using those) - UsbTransfer& get_transfer(u32 transfer_id); - u32 get_free_transfer_id(); - - void send_message(u32 message, u32 tr_id); - void perform_scan(); - -private: - // Counters for device IDs, transfer IDs and pipe IDs - atomic_t dev_counter = 1; - u32 transfer_counter = 0; - u32 pipe_counter = 0x10; // Start at 0x10 only for tracing purposes - - // List of device drivers - std::unordered_map> ldds; - - const std::vector device_allow_list{ - // Portals - {0x1430, 0x0150, 0x0150, "Skylanders Portal", &usb_device_skylander::get_num_emu_devices, &usb_device_skylander::make_instance}, - {0x0E6F, 0x0129, 0x0129, "Disney Infinity Base", &usb_device_infinity::get_num_emu_devices, &usb_device_infinity::make_instance}, - {0x0E6F, 0x0241, 0x0241, "Lego Dimensions Portal", &usb_device_dimensions::get_num_emu_devices, &usb_device_dimensions::make_instance}, - {0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal", nullptr, nullptr}, - - // Cameras - // {0x1415, 0x0020, 0x2000, "Sony Playstation Eye", nullptr, nullptr}, // TODO: verifiy - - // Music devices - {0x1415, 0x0000, 0x0000, "Singstar Microphone", nullptr, nullptr}, - // {0x1415, 0x0020, 0x0020, "SingStar Microphone Wireless", nullptr, nullptr}, // TODO: verifiy - - {0x12BA, 0x00FF, 0x00FF, "Rocksmith Guitar Adapter", nullptr, nullptr}, - {0x12BA, 0x0100, 0x0100, "Guitar Hero Guitar", nullptr, nullptr}, - {0x12BA, 0x0120, 0x0120, "Guitar Hero Drums", nullptr, nullptr}, - {0x12BA, 0x074B, 0x074B, "Guitar Hero Live Guitar", &usb_device_ghltar::get_num_emu_devices, &usb_device_ghltar::make_instance}, - - {0x12BA, 0x0140, 0x0140, "DJ Hero Turntable", &usb_device_turntable::get_num_emu_devices, &usb_device_turntable::make_instance}, - {0x12BA, 0x0200, 0x020F, "Harmonix Guitar", nullptr, nullptr}, - {0x12BA, 0x0210, 0x021F, "Harmonix Drums", nullptr, nullptr}, - {0x12BA, 0x2330, 0x233F, "Harmonix Keyboard", nullptr, nullptr}, - {0x12BA, 0x2430, 0x243F, "Harmonix Button Guitar", nullptr, nullptr}, - {0x12BA, 0x2530, 0x253F, "Harmonix Real Guitar", nullptr, nullptr}, - - {0x1BAD, 0x0004, 0x0004, "Harmonix RB1 Guitar - Wii", nullptr, nullptr}, - {0x1BAD, 0x0005, 0x0005, "Harmonix RB1 Drums - Wii", nullptr, nullptr}, - {0x1BAD, 0x3010, 0x301F, "Harmonix RB2 Guitar - Wii", nullptr, nullptr}, - {0x1BAD, 0x3110, 0x313F, "Harmonix RB2 Drums - Wii", nullptr, nullptr}, - {0x1BAD, 0x3330, 0x333F, "Harmonix Keyboard - Wii", nullptr, nullptr}, - {0x1BAD, 0x3430, 0x343F, "Harmonix Button Guitar - Wii", nullptr, nullptr}, - {0x1BAD, 0x3530, 0x353F, "Harmonix Real Guitar - Wii", nullptr, nullptr}, - - // Top Shot Elite controllers - {0x12BA, 0x04A0, 0x04A0, "Top Shot Elite", nullptr, nullptr}, - {0x12BA, 0x04A1, 0x04A1, "Top Shot Fearmaster", nullptr, nullptr}, - {0x12BA, 0x04B0, 0x04B0, "Rapala Fishing Rod", nullptr, nullptr}, - - // GT5 Wheels&co - {0x046D, 0xC283, 0xC29B, "lgFF_c283_c29b", nullptr, nullptr}, - {0x044F, 0xB653, 0xB653, "Thrustmaster RGT FFB Pro", nullptr, nullptr}, - {0x044F, 0xB65A, 0xB65A, "Thrustmaster F430", nullptr, nullptr}, - {0x044F, 0xB65D, 0xB65D, "Thrustmaster FFB", nullptr, nullptr}, - {0x044F, 0xB65E, 0xB65E, "Thrustmaster TRS", nullptr, nullptr}, - {0x044F, 0xB660, 0xB660, "Thrustmaster T500 RS Gear Shift", nullptr, nullptr}, - - // GT6 - {0x2833, 0x0001, 0x0001, "Oculus", nullptr, nullptr}, - {0x046D, 0xCA03, 0xCA03, "lgFF_ca03_ca03", nullptr, nullptr}, - - // Buzz controllers - {0x054C, 0x1000, 0x1040, "buzzer0", &usb_device_buzz::get_num_emu_devices, &usb_device_buzz::make_instance}, - {0x054C, 0x0001, 0x0041, "buzzer1", nullptr, nullptr}, - {0x054C, 0x0042, 0x0042, "buzzer2", nullptr, nullptr}, - {0x046D, 0xC220, 0xC220, "buzzer9", nullptr, nullptr}, - - // GCon3 Gun - {0x0B9A, 0x0800, 0x0800, "guncon3", nullptr, nullptr}, - - // uDraw GameTablet - {0x20D6, 0xCB17, 0xCB17, "uDraw GameTablet", nullptr, nullptr}, - - // DVB-T - {0x1415, 0x0003, 0x0003, "PlayTV SCEH-0036", nullptr, nullptr}, - - // PSP Devices - {0x054C, 0x01C8, 0x01C8, "PSP Type A", nullptr, nullptr}, - {0x054C, 0x01C9, 0x01C9, "PSP Type B", nullptr, nullptr}, - {0x054C, 0x01CA, 0x01CA, "PSP Type C", nullptr, nullptr}, - {0x054C, 0x01CB, 0x01CB, "PSP Type D", nullptr, nullptr}, - {0x054C, 0x02D2, 0x02D2, "PSP Slim", nullptr, nullptr}, - - // 0x0900: "H050 USJ(C) PCB rev00", 0x0910: "USIO PCB rev00" - {0x0B9A, 0x0900, 0x0910, "PS3A-USJ", &usb_device_usio::get_num_emu_devices, &usb_device_usio::make_instance}, - - // Densha de GO! controller - {0x0AE4, 0x0004, 0x0004, "Densha de GO! Type 2 Controller", nullptr, nullptr}, - - // EA Active 2 dongle for connecting wristbands & legband - {0x21A4, 0xAC27, 0xAC27, "EA Active 2 Dongle", nullptr, nullptr}, - - // Tony Hawk RIDE Skateboard - {0x12BA, 0x0400, 0x0400, "Tony Hawk RIDE Skateboard Controller", nullptr, nullptr}, - - // PSP in UsbPspCm mode - {0x054C, 0x01CB, 0x01CB, "UsbPspcm", nullptr, nullptr}, - - // Sony Stereo Headsets - {0x12BA, 0x0032, 0x0032, "Wireless Stereo Headset", nullptr, nullptr}, - {0x12BA, 0x0042, 0x0042, "Wireless Stereo Headset", nullptr, nullptr}, - }; - - // List of pipes - std::map open_pipes; - // Transfers infos - shared_mutex mutex_transfers; - std::array transfers; - std::vector fake_transfers; - - // Queue of pending usbd events - std::queue> usbd_events; - - // List of devices "connected" to the ps3 - std::array location{}; - std::vector> usb_devices; - std::unordered_map> usb_passthrough_devices; - - libusb_context* ctx = nullptr; - -#if LIBUSB_API_VERSION >= 0x01000102 - libusb_hotplug_callback_handle callback_handle{}; -#endif - - bool hotplug_supported = false; -}; - -void LIBUSB_CALL callback_transfer(struct libusb_transfer* transfer) -{ - auto& usbh = g_fxo->get>(); - - if (!usbh.is_init) - return; - - usbh.transfer_complete(transfer); -} - -#if LIBUSB_API_VERSION >= 0x01000102 -static int LIBUSB_CALL hotplug_callback(libusb_context* /*ctx*/, libusb_device* /*dev*/, libusb_hotplug_event event, void* /*user_data*/) -{ - handle_hotplug_event(event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED); - return 0; -} -#endif - -#if LIBUSB_API_VERSION >= 0x0100010A -static void LIBUSB_CALL log_cb(libusb_context* /*ctx*/, enum libusb_log_level level, const char* str) -{ - if (!str) - return; - - const std::string msg = fmt::trim(str, " \t\n"); - - switch (level) - { - case LIBUSB_LOG_LEVEL_ERROR: - sys_usbd.error("libusb log: %s", msg); - break; - case LIBUSB_LOG_LEVEL_WARNING: - sys_usbd.warning("libusb log: %s", msg); - break; - case LIBUSB_LOG_LEVEL_INFO: - sys_usbd.notice("libusb log: %s", msg); - break; - case LIBUSB_LOG_LEVEL_DEBUG: - sys_usbd.trace("libusb log: %s", msg); - break; - default: - break; - } -} -#endif - -void usb_handler_thread::perform_scan() -{ - // look if any device which we could be interested in is actually connected - libusb_device** list = nullptr; - const ssize_t ndev = libusb_get_device_list(ctx, &list); - std::set seen_usb_devices; - - if (ndev < 0) - { - sys_usbd.error("Failed to get device list: %s", libusb_error_name(static_cast(ndev))); - return; - } - - for (ssize_t index = 0; index < ndev; index++) - { - libusb_device* dev = list[index]; - libusb_device_descriptor desc; - if (int res = libusb_get_device_descriptor(dev, &desc); res < 0) - { - sys_usbd.error("Failed to get device descriptor: %s", libusb_error_name(res)); - continue; - } - - const u8 port = libusb_get_port_number(dev); - const u8 address = libusb_get_device_address(dev); - const u64 usb_id = (static_cast(desc.idVendor) << 48) | (static_cast(desc.idProduct) << 32) | (static_cast(port) << 8) | address; - - seen_usb_devices.insert(usb_id); - if (usb_passthrough_devices.contains(usb_id)) - { - continue; - } - - for (const auto& entry : device_allow_list) - { - // attach - if (desc.idVendor == entry.id_vendor && desc.idProduct >= entry.id_product_min && desc.idProduct <= entry.id_product_max) - { - sys_usbd.success("Found device: %s", std::basic_string(entry.device_name)); - libusb_ref_device(dev); - std::shared_ptr usb_dev = std::make_shared(dev, desc, get_new_location()); - connect_usb_device(usb_dev, true); - usb_passthrough_devices[usb_id] = usb_dev; - } - } - - if (desc.idVendor == 0x1209 && desc.idProduct == 0x2882) - { - sys_usbd.success("Found device: Santroller"); - // Send the device a specific control transfer so that it jumps to a RPCS3 compatible mode - libusb_device_handle* lusb_handle; - if (libusb_open(dev, &lusb_handle) == LIBUSB_SUCCESS) - { -#ifdef __linux__ - libusb_set_auto_detach_kernel_driver(lusb_handle, true); - libusb_claim_interface(lusb_handle, 2); -#endif - libusb_control_transfer(lusb_handle, +LIBUSB_ENDPOINT_IN | +LIBUSB_REQUEST_TYPE_CLASS | +LIBUSB_RECIPIENT_INTERFACE, 0x01, 0x03f2, 2, nullptr, 0, 5000); - libusb_close(lusb_handle); - } - else - { - sys_usbd.error("Unable to open Santroller device, make sure Santroller isn't open in the background."); - } - } - } - - for (auto it = usb_passthrough_devices.begin(); it != usb_passthrough_devices.end();) - { - auto& dev = *it; - // If a device is no longer visible, disconnect it - if (seen_usb_devices.contains(dev.first)) - { - ++it; - } - else - { - disconnect_usb_device(dev.second, true); - it = usb_passthrough_devices.erase(it); - } - } - libusb_free_device_list(list, 1); -} - -usb_handler_thread::usb_handler_thread() -{ -#if LIBUSB_API_VERSION >= 0x0100010A - libusb_init_option log_lv_opt{}; - log_lv_opt.option = LIBUSB_OPTION_LOG_LEVEL; - log_lv_opt.value.ival = LIBUSB_LOG_LEVEL_WARNING; // You can also set the LIBUSB_DEBUG env variable instead - - libusb_init_option log_cb_opt{}; - log_cb_opt.option = LIBUSB_OPTION_LOG_CB; - log_cb_opt.value.log_cbval = &log_cb; - - std::vector options = { - std::move(log_lv_opt), - std::move(log_cb_opt)}; - - if (int res = libusb_init_context(&ctx, options.data(), static_cast(options.size())); res < 0) -#else - if (int res = libusb_init(&ctx); res < 0) -#endif - { - sys_usbd.error("Failed to initialize sys_usbd: %s", libusb_error_name(res)); - return; - } - -#ifdef _WIN32 - hotplug_supported = true; -#elif LIBUSB_API_VERSION >= 0x01000102 - if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) - { - if (int res = libusb_hotplug_register_callback(ctx, static_cast(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), static_cast(0), LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, static_cast(hotplug_callback), nullptr, - &callback_handle); - res < 0) - { - sys_usbd.error("Failed to initialize sys_usbd hotplug: %s", libusb_error_name(res)); - } - else - { - hotplug_supported = true; - } - } -#endif - - for (u32 index = 0; index < MAX_SYS_USBD_TRANSFERS; index++) - { - transfers[index].transfer = libusb_alloc_transfer(8); - transfers[index].transfer_id = index; - } - - if (!g_cfg_usio.load()) - { - sys_usbd.notice("Could not load usio config. Using defaults."); - } - - sys_usbd.notice("USIO config=\n", g_cfg_usio.to_string()); - - if (g_cfg.io.ghltar == ghltar_handler::one_controller || g_cfg.io.ghltar == ghltar_handler::two_controllers) - { - if (!g_cfg_ghltar.load()) - { - sys_usbd.notice("Could not load ghltar config. Using defaults."); - } - - sys_usbd.notice("Ghltar config=\n", g_cfg_ghltar.to_string()); - } - - if (g_cfg.io.turntable == turntable_handler::one_controller || g_cfg.io.turntable == turntable_handler::two_controllers) - { - if (!g_cfg_turntable.load()) - { - sys_usbd.notice("Could not load turntable config. Using defaults."); - } - - sys_usbd.notice("Turntable config=\n", g_cfg_turntable.to_string()); - } - - if (g_cfg.io.buzz == buzz_handler::one_controller || g_cfg.io.buzz == buzz_handler::two_controllers) - { - if (!g_cfg_buzz.load()) - { - sys_usbd.notice("Could not load buzz config. Using defaults."); - } - - sys_usbd.notice("Buzz config=\n", g_cfg_buzz.to_string()); - } - - perform_scan(); - - // Set up emulated devices for any devices that are not already being passed through - std::map passthrough_usb_device_counts; - for (const auto& dev : usb_devices) - { - for (const auto& entry : device_allow_list) - { - const u16 idVendor = dev->device._device.idVendor; - const u16 idProduct = dev->device._device.idProduct; - if (entry.max_device_count != nullptr && (idVendor == entry.id_vendor && idProduct >= entry.id_product_min && idProduct <= entry.id_product_max)) - { - passthrough_usb_device_counts[entry]++; - } - } - } - - for (const auto& entry : device_allow_list) - { - if (entry.max_device_count && entry.make_instance) - { - const int count = passthrough_usb_device_counts[entry]; - for (int i = count; i < entry.max_device_count(); i++) - { - sys_usbd.success("Emulating device: %s (%d)", std::basic_string(entry.device_name), i + 1); - auto usb_dev = entry.make_instance(i, get_new_location()); - connect_usb_device(usb_dev, true); - } - } - } - - for (int i = 0; i < 8; i++) // Add VFS USB mass storage devices (/dev_usbXXX) to the USB device list - { - const auto usb_info = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/dev_usb%03d", i)); - if (fs::is_dir(usb_info.path)) - usb_devices.push_back(std::make_shared(usb_info, get_new_location())); - } - - const std::vector devices_list = fmt::split(g_cfg.io.midi_devices.to_string(), {"@@@"}); - for (usz index = 0; index < std::min(max_midi_devices, devices_list.size()); index++) - { - const midi_device device = midi_device::from_string(::at32(devices_list, index)); - if (device.name.empty()) - continue; - - sys_usbd.notice("Adding Emulated Midi Pro Adapter (type=%s, name=%s)", device.type, device.name); - - switch (device.type) - { - case midi_device_type::guitar: - usb_devices.push_back(std::make_shared(get_new_location(), device.name, false)); - break; - case midi_device_type::guitar_22fret: - usb_devices.push_back(std::make_shared(get_new_location(), device.name, true)); - break; - case midi_device_type::keyboard: - usb_devices.push_back(std::make_shared(get_new_location(), device.name)); - break; - case midi_device_type::drums: - if (!g_cfg_rb3drums.load()) - { - sys_usbd.notice("Could not load rb3drums config. Using defaults."); - } - - usb_devices.push_back(std::make_shared(get_new_location(), device.name)); - - sys_usbd.notice("RB3 drums config=\n", g_cfg_rb3drums.to_string()); - break; - } - } -} - -usb_handler_thread::~usb_handler_thread() -{ - // Ensures shared_ptr are all cleared before terminating libusb - handled_devices.clear(); - open_pipes.clear(); - usb_devices.clear(); - usb_passthrough_devices.clear(); - - for (u32 index = 0; index < MAX_SYS_USBD_TRANSFERS; index++) - { - if (transfers[index].transfer) - libusb_free_transfer(transfers[index].transfer); - } - -#if LIBUSB_API_VERSION >= 0x01000102 - if (ctx && hotplug_supported) - libusb_hotplug_deregister_callback(ctx, callback_handle); -#endif - - if (ctx) - libusb_exit(ctx); -} - -void usb_handler_thread::operator()() -{ - timeval lusb_tv{0, 0}; - if (!hotplug_supported) - { - usb_hotplug_timeout = get_system_time() + 4'000'000ull; - } - while (ctx && thread_ctrl::state() != thread_state::aborting) - { - const u64 now = get_system_time(); - if (now > usb_hotplug_timeout) - { - // If we did the hotplug scan each cycle the game performance was significantly degraded, so we only perform this scan - // every 4 seconds. - // On systems where hotplug is native, we wait a little bit for devices to settle before we start the scan - perform_scan(); - usb_hotplug_timeout = hotplug_supported ? umax : get_system_time() + 4'000'000ull; - } - - // Process asynchronous requests that are pending - libusb_handle_events_timeout_completed(ctx, &lusb_tv, nullptr); - - // Process fake transfers - if (!fake_transfers.empty()) - { - std::lock_guard lock_tf(mutex_transfers); - u64 timestamp = get_system_time() - Emu.GetPauseTime(); - - for (auto it = fake_transfers.begin(); it != fake_transfers.end();) - { - auto transfer = *it; - - ensure(transfer->busy && transfer->fake); - - if (transfer->expected_time > timestamp) - { - ++it; - continue; - } - - transfer->result = transfer->expected_result; - transfer->count = transfer->expected_count; - transfer->fake = false; - transfer->busy = false; - - send_message(SYS_USBD_TRANSFER_COMPLETE, transfer->transfer_id); - it = fake_transfers.erase(it); // if we've processed this, then we erase this entry (replacing the iterator with the new reference) - } - } - - // If there is no handled devices usb thread is not actively needed - if (handled_devices.empty()) - thread_ctrl::wait_for(500'000); - else - thread_ctrl::wait_for(1'000); - } -} - -void usb_handler_thread::send_message(u32 message, u32 tr_id) -{ - add_event(message, tr_id, 0x00); -} - -void usb_handler_thread::transfer_complete(struct libusb_transfer* transfer) -{ - std::lock_guard lock_tf(mutex_transfers); - - UsbTransfer* usbd_transfer = static_cast(transfer->user_data); - - if (transfer->status != 0) - { - sys_usbd.error("Transfer Error: %d", +transfer->status); - } - - switch (transfer->status) - { - case LIBUSB_TRANSFER_COMPLETED: usbd_transfer->result = HC_CC_NOERR; break; - case LIBUSB_TRANSFER_TIMED_OUT: usbd_transfer->result = EHCI_CC_XACT; break; - case LIBUSB_TRANSFER_OVERFLOW: usbd_transfer->result = EHCI_CC_BABBLE; break; - case LIBUSB_TRANSFER_NO_DEVICE: - usbd_transfer->result = EHCI_CC_HALTED; - for (const auto& dev : usb_devices) - { - if (dev->assigned_number == usbd_transfer->assigned_number) - { - disconnect_usb_device(dev, true); - break; - } - } - break; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - case LIBUSB_TRANSFER_STALL: - default: - usbd_transfer->result = EHCI_CC_HALTED; - break; - } - - usbd_transfer->count = transfer->actual_length; - - for (s32 index = 0; index < transfer->num_iso_packets; index++) - { - u8 iso_status; - switch (transfer->iso_packet_desc[index].status) - { - case LIBUSB_TRANSFER_COMPLETED: iso_status = USBD_HC_CC_NOERR; break; - case LIBUSB_TRANSFER_TIMED_OUT: iso_status = USBD_HC_CC_XACT; break; - case LIBUSB_TRANSFER_OVERFLOW: iso_status = USBD_HC_CC_BABBLE; break; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - case LIBUSB_TRANSFER_STALL: - case LIBUSB_TRANSFER_NO_DEVICE: - default: iso_status = USBD_HC_CC_MISSMF; break; - } - - usbd_transfer->iso_request.packets[index] = ((iso_status & 0xF) << 12 | (transfer->iso_packet_desc[index].actual_length & 0xFFF)); - } - - if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL && usbd_transfer->control_destbuf) - { - memcpy(usbd_transfer->control_destbuf, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer->actual_length); - usbd_transfer->control_destbuf = nullptr; - } - - usbd_transfer->busy = false; - - send_message(SYS_USBD_TRANSFER_COMPLETE, usbd_transfer->transfer_id); - - sys_usbd.trace("Transfer complete(0x%x): %s", usbd_transfer->transfer_id, *transfer); -} - -bool usb_handler_thread::add_ldd(std::string_view product, u16 id_vendor, u16 id_product_min, u16 id_product_max) -{ - if (ldds.try_emplace(std::string(product), UsbLdd{id_vendor, id_product_min, id_product_max}).second) - { - for (const auto& dev : usb_devices) - { - if (dev->assigned_number) - continue; - - if (dev->device._device.idVendor == id_vendor && dev->device._device.idProduct >= id_product_min && dev->device._device.idProduct <= id_product_max) - { - connect_usb_device(dev); - } - } - - return true; - } - - return false; -} - -bool usb_handler_thread::remove_ldd(std::string_view product) -{ - if (const auto iterator = ldds.find(product); iterator != ldds.end()) - { - for (const auto& dev : usb_devices) - { - if (!dev->assigned_number) - continue; - - if (dev->device._device.idVendor == iterator->second.id_vendor && dev->device._device.idProduct >= iterator->second.id_product_min && dev->device._device.idProduct <= iterator->second.id_product_max) - { - disconnect_usb_device(dev); - } - } - - ldds.erase(iterator); - return true; - } - - return false; -} - -u32 usb_handler_thread::open_pipe(u32 device_handle, u8 endpoint) -{ - open_pipes.emplace(pipe_counter, UsbPipe{handled_devices[device_handle].second, endpoint}); - return pipe_counter++; -} - -bool usb_handler_thread::close_pipe(u32 pipe_id) -{ - return open_pipes.erase(pipe_id) != 0; -} - -bool usb_handler_thread::is_pipe(u32 pipe_id) const -{ - return open_pipes.count(pipe_id) != 0; -} - -const UsbPipe& usb_handler_thread::get_pipe(u32 pipe_id) const -{ - return ::at32(open_pipes, pipe_id); -} - -bool usb_handler_thread::get_event(vm::ptr& arg1, vm::ptr& arg2, vm::ptr& arg3) -{ - if (!usbd_events.empty()) - { - const auto& usb_event = usbd_events.front(); - *arg1 = std::get<0>(usb_event); - *arg2 = std::get<1>(usb_event); - *arg3 = std::get<2>(usb_event); - usbd_events.pop(); - sys_usbd.trace("Received event: arg1=0x%x arg2=0x%x arg3=0x%x", *arg1, *arg2, *arg3); - return true; - } - - return false; -} - -void usb_handler_thread::add_event(u64 arg1, u64 arg2, u64 arg3) -{ - // sys_usbd events use an internal event queue with SYS_SYNC_PRIORITY protocol - std::lock_guard lock_sq(mutex_sq); - - if (const auto cpu = lv2_obj::schedule(sq, SYS_SYNC_PRIORITY)) - { - sys_usbd.trace("Sending event(queue): arg1=0x%x arg2=0x%x arg3=0x%x", arg1, arg2, arg3); - cpu->gpr[4] = arg1; - cpu->gpr[5] = arg2; - cpu->gpr[6] = arg3; - lv2_obj::awake(cpu); - } - else - { - sys_usbd.trace("Sending event: arg1=0x%x arg2=0x%x arg3=0x%x", arg1, arg2, arg3); - usbd_events.emplace(arg1, arg2, arg3); - } -} - -u32 usb_handler_thread::get_free_transfer_id() -{ - u32 num_loops = 0; - do - { - num_loops++; - transfer_counter++; - - if (transfer_counter >= MAX_SYS_USBD_TRANSFERS) - { - transfer_counter = 0; - } - - if (num_loops > MAX_SYS_USBD_TRANSFERS) - { - sys_usbd.fatal("Usb transfers are saturated!"); - } - } while (transfers[transfer_counter].busy); - - return transfer_counter; -} - -UsbTransfer& usb_handler_thread::get_transfer(u32 transfer_id) -{ - return transfers[transfer_id]; -} - -std::pair usb_handler_thread::get_free_transfer() -{ - std::lock_guard lock_tf(mutex_transfers); - - u32 transfer_id = get_free_transfer_id(); - auto& transfer = get_transfer(transfer_id); - transfer.busy = true; - - return {transfer_id, transfer}; -} - -std::pair usb_handler_thread::get_transfer_status(u32 transfer_id) -{ - std::lock_guard lock_tf(mutex_transfers); - - const auto& transfer = get_transfer(transfer_id); - - return {transfer.result, transfer.count}; -} - -std::pair usb_handler_thread::get_isochronous_transfer_status(u32 transfer_id) -{ - std::lock_guard lock_tf(mutex_transfers); - - const auto& transfer = get_transfer(transfer_id); - - return {transfer.result, transfer.iso_request}; -} - -void usb_handler_thread::push_fake_transfer(UsbTransfer* transfer) -{ - std::lock_guard lock_tf(mutex_transfers); - fake_transfers.push_back(transfer); -} - -const std::array& usb_handler_thread::get_new_location() -{ - location[0]++; - return location; -} - -void usb_handler_thread::connect_usb_device(std::shared_ptr dev, bool update_usb_devices) -{ - if (update_usb_devices) - usb_devices.push_back(dev); - - for (const auto& [name, ldd] : ldds) - { - if (dev->device._device.idVendor == ldd.id_vendor && dev->device._device.idProduct >= ldd.id_product_min && dev->device._device.idProduct <= ldd.id_product_max) - { - if (!dev->open_device()) - { - sys_usbd.error("Failed to open USB device(VID=0x%04x, PID=0x%04x) for LDD <%s>", dev->device._device.idVendor, dev->device._device.idProduct, name); - disconnect_usb_device(dev); - return; - } - - dev->read_descriptors(); - dev->assigned_number = dev_counter++; // assign current dev_counter, and atomically increment0 - handled_devices.emplace(dev->assigned_number, std::pair(UsbInternalDevice{0x00, narrow(dev->assigned_number), 0x02, 0x40}, dev)); - send_message(SYS_USBD_ATTACH, dev->assigned_number); - sys_usbd.success("USB device(VID=0x%04x, PID=0x%04x) matches up with LDD <%s>, assigned as handled_device=0x%x", dev->device._device.idVendor, dev->device._device.idProduct, name, dev->assigned_number); - return; - } - } -} - -void usb_handler_thread::disconnect_usb_device(std::shared_ptr dev, bool update_usb_devices) -{ - if (dev->assigned_number && handled_devices.erase(dev->assigned_number)) - { - send_message(SYS_USBD_DETACH, dev->assigned_number); - sys_usbd.success("USB device(VID=0x%04x, PID=0x%04x) unassigned, handled_device=0x%x", dev->device._device.idVendor, dev->device._device.idProduct, dev->assigned_number); - dev->assigned_number = 0; - std::erase_if(open_pipes, [&](const auto& val) - { - return val.second.device == dev; - }); - } - if (update_usb_devices) - { - std::erase_if(usb_devices, [&](const auto& val) - { - return val == dev; - }); - } -} - -void connect_usb_controller(u8 index, input::product_type type) -{ - auto usbh = g_fxo->try_get>(); - if (!usbh) - { - return; - } - - bool already_connected = false; - - if (const auto it = usbh->pad_to_usb.find(index); it != usbh->pad_to_usb.end()) - { - if (it->second.first == type) - { - already_connected = true; - } - else - { - usbh->disconnect_usb_device(it->second.second, true); - usbh->pad_to_usb.erase(it->first); - } - } - - if (!already_connected) - { - switch (type) - { - case input::product_type::guncon_3: - { - if (!g_cfg_guncon3.load()) - { - sys_usbd.notice("Could not load GunCon3 config. Using defaults."); - } - - sys_usbd.success("Adding emulated GunCon3 (controller %d)", index); - std::shared_ptr dev = std::make_shared(index, usbh->get_new_location()); - usbh->connect_usb_device(dev, true); - usbh->pad_to_usb.emplace(index, std::pair(type, dev)); - - sys_usbd.notice("GunCon3 config=\n", g_cfg_guncon3.to_string()); - break; - } - case input::product_type::top_shot_elite: - { - if (!g_cfg_topshotelite.load()) - { - sys_usbd.notice("Could not load Top Shot Elite config. Using defaults."); - } - - sys_usbd.success("Adding emulated Top Shot Elite (controller %d)", index); - std::shared_ptr dev = std::make_shared(index, usbh->get_new_location()); - usbh->connect_usb_device(dev, true); - usbh->pad_to_usb.emplace(index, std::pair(type, dev)); - - sys_usbd.notice("Top shot elite config=\n", g_cfg_topshotelite.to_string()); - break; - } - case input::product_type::top_shot_fearmaster: - { - if (!g_cfg_topshotfearmaster.load()) - { - sys_usbd.notice("Could not load Top Shot Fearmaster config. Using defaults."); - } - - sys_usbd.success("Adding emulated Top Shot Fearmaster (controller %d)", index); - std::shared_ptr dev = std::make_shared(index, usbh->get_new_location()); - usbh->connect_usb_device(dev, true); - usbh->pad_to_usb.emplace(index, std::pair(type, dev)); - - sys_usbd.notice("Top shot fearmaster config=\n", g_cfg_topshotfearmaster.to_string()); - break; - } - case input::product_type::udraw_gametablet: - { - sys_usbd.success("Adding emulated uDraw GameTablet (controller %d)", index); - std::shared_ptr dev = std::make_shared(index, usbh->get_new_location()); - usbh->connect_usb_device(dev, true); - usbh->pad_to_usb.emplace(index, std::pair(type, dev)); - break; - } - default: - break; - } - } -} - -void handle_hotplug_event(bool connected) -{ - if (auto usbh = g_fxo->try_get>()) - { - usbh->usb_hotplug_timeout = get_system_time() + (connected ? 1'000'000ull : 0); - } -} error_code sys_usbd_initialize(ppu_thread& ppu, vm::ptr handle) { ppu.state += cpu_flag::wait; - sys_usbd.warning("sys_usbd_initialize(handle=*0x%x)", handle); - - auto& usbh = g_fxo->get>(); - - { - std::lock_guard lock(usbh.mutex); - - // Must not occur (lv2 allows multiple handles, cellUsbd does not) - ensure(!usbh.is_init.exchange(true)); - } + sys_usbd.todo("sys_usbd_initialize(handle=*0x%x)", handle); ppu.check_state(); *handle = 0x115B; @@ -1060,22 +33,7 @@ error_code sys_usbd_finalize(ppu_thread& ppu, u32 handle) { ppu.state += cpu_flag::wait; - sys_usbd.warning("sys_usbd_finalize(handle=0x%x)", handle); - - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - usbh.is_init = false; - - // Forcefully awake all waiters - while (auto cpu = lv2_obj::schedule(usbh.sq, SYS_SYNC_FIFO)) - { - // Special ternimation signal value - cpu->gpr[4] = 4; - cpu->gpr[5] = 0; - cpu->gpr[6] = 0; - lv2_obj::awake(cpu); - } + sys_usbd.todo("sys_usbd_finalize(handle=0x%x)", handle); // TODO return CELL_OK; @@ -1085,110 +43,49 @@ error_code sys_usbd_get_device_list(ppu_thread& ppu, u32 handle, vm::ptrget>(); + sys_usbd.todo("sys_usbd_get_device_list(handle=0x%x, device_list=*0x%x, max_devices=0x%x)", handle, device_list, max_devices); - std::lock_guard lock(usbh.mutex); - if (!usbh.is_init) - return CELL_EINVAL; - - // TODO: was std::min - u32 i_tocopy = std::min(max_devices, ::size32(usbh.handled_devices)); - - for (u32 index = 0; index < i_tocopy; index++) - { - device_list[index] = usbh.handled_devices[index].first; - } - - return not_an_error(i_tocopy); + return CELL_OK; } error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max) { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_register_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d, id_vendor=0x%04x, id_product_min=0x%04x, id_product_max=0x%04x)", handle, s_product, slen_product, id_vendor, id_product_min, id_product_max); - - auto& usbh = g_fxo->get>(); + sys_usbd.todo("sys_usbd_register_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d, id_vendor=0x%04x, id_product_min=0x%04x, id_product_max=0x%04x)", handle, s_product, slen_product, id_vendor, id_product_min, id_product_max); - std::lock_guard lock(usbh.mutex); - if (!usbh.is_init) - return CELL_EINVAL; - - std::string_view product{s_product.get_ptr(), slen_product}; - - if (usbh.add_ldd(product, id_vendor, id_product_min, id_product_max)) - return CELL_OK; - - return CELL_EEXIST; + return CELL_OK; } error_code sys_usbd_unregister_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr s_product, u16 slen_product) { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_unregister_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d)", handle, s_product, slen_product); - - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - if (!usbh.is_init) - return CELL_EINVAL; + sys_usbd.todo("sys_usbd_unregister_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d)", handle, s_product, slen_product); - std::string_view product{s_product.get_ptr(), slen_product}; - - if (usbh.remove_ldd(product)) - return CELL_OK; - - return CELL_ESRCH; + return CELL_OK; } error_code sys_usbd_get_descriptor_size(ppu_thread& ppu, u32 handle, u32 device_handle) { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_get_descriptor_size(handle=0x%x, deviceNumber=0x%x)", handle, device_handle); - - auto& usbh = g_fxo->get>(); + sys_usbd.todo("sys_usbd_get_descriptor_size(handle=0x%x, deviceNumber=0x%x)", handle, device_handle); - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.handled_devices.count(device_handle)) - { - return CELL_EINVAL; - } - - return not_an_error(usbh.handled_devices[device_handle].second->device.get_size()); + return CELL_OK; } error_code sys_usbd_get_descriptor(ppu_thread& ppu, u32 handle, u32 device_handle, vm::ptr descriptor, u32 desc_size) { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_get_descriptor(handle=0x%x, deviceNumber=0x%x, descriptor=0x%x, desc_size=0x%x)", handle, device_handle, descriptor, desc_size); + sys_usbd.todo("sys_usbd_get_descriptor(handle=0x%x, deviceNumber=0x%x, descriptor=0x%x, desc_size=0x%x)", handle, device_handle, descriptor, desc_size); if (!descriptor) { return CELL_EINVAL; } - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.handled_devices.count(device_handle)) - { - return CELL_EINVAL; - } - - if (!desc_size) - { - return CELL_ENOMEM; - } - - usbh.handled_devices[device_handle].second->device.write_data(reinterpret_cast(descriptor.get_ptr()), desc_size); - return CELL_OK; } @@ -1232,36 +129,18 @@ error_code sys_usbd_open_pipe(ppu_thread& ppu, u32 handle, u32 device_handle, u3 { ppu.state += cpu_flag::wait; - 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, attributes=0x%x)", handle, device_handle, unk1, unk2, unk3, endpoint, attributes); - - auto& usbh = g_fxo->get>(); + sys_usbd.todo("sys_usbd_open_pipe(handle=0x%x, device_handle=0x%x, unk1=0x%x, unk2=0x%x, unk3=0x%x, endpoint=0x%x, attributes=0x%x)", handle, device_handle, unk1, unk2, unk3, endpoint, attributes); - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.handled_devices.count(device_handle)) - { - return CELL_EINVAL; - } - - return not_an_error(usbh.open_pipe(device_handle, static_cast(endpoint))); + return CELL_OK; } error_code sys_usbd_open_default_pipe(ppu_thread& ppu, u32 handle, u32 device_handle) { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_open_default_pipe(handle=0x%x, device_handle=0x%x)", handle, device_handle); + sys_usbd.todo("sys_usbd_open_default_pipe(handle=0x%x, device_handle=0x%x)", handle, device_handle); - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.handled_devices.count(device_handle)) - { - return CELL_EINVAL; - } - - return not_an_error(usbh.open_pipe(device_handle, 0)); + return CELL_OK; } error_code sys_usbd_close_pipe(ppu_thread& ppu, u32 handle, u32 pipe_handle) @@ -1270,17 +149,6 @@ error_code sys_usbd_close_pipe(ppu_thread& ppu, u32 handle, u32 pipe_handle) sys_usbd.todo("sys_usbd_close_pipe(handle=0x%x, pipe_handle=0x%x)", handle, pipe_handle); - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.is_pipe(pipe_handle)) - { - return CELL_EINVAL; - } - - usbh.close_pipe(pipe_handle); - return CELL_OK; } @@ -1294,57 +162,7 @@ error_code sys_usbd_receive_event(ppu_thread& ppu, u32 handle, vm::ptr arg1 { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_receive_event(handle=0x%x, arg1=*0x%x, arg2=*0x%x, arg3=*0x%x)", handle, arg1, arg2, arg3); - - auto& usbh = g_fxo->get>(); - - { - std::lock_guard lock_sq(usbh.mutex_sq); - - if (!usbh.is_init) - return CELL_EINVAL; - - if (usbh.get_event(arg1, arg2, arg3)) - { - // hack for Guitar Hero Live - // Attaching the device too fast seems to result in a nullptr along the way - if (*arg1 == SYS_USBD_ATTACH) - lv2_obj::sleep(ppu), lv2_obj::wait_timeout(5000); - - return CELL_OK; - } - - lv2_obj::sleep(ppu); - lv2_obj::emplace(usbh.sq, &ppu); - } - - while (auto state = +ppu.state) - { - if (state & cpu_flag::signal && ppu.state.test_and_reset(cpu_flag::signal)) - { - sys_usbd.trace("Received event(queued): arg1=0x%x arg2=0x%x arg3=0x%x", ppu.gpr[4], ppu.gpr[5], ppu.gpr[6]); - break; - } - - if (is_stopped(state)) - { - std::lock_guard lock(usbh.mutex); - - for (auto cpu = +usbh.sq; cpu; cpu = cpu->next_cpu) - { - if (cpu == &ppu) - { - ppu.state += cpu_flag::again; - sys_usbd.trace("sys_usbd_receive_event: aborting"); - return {}; - } - } - - break; - } - - ppu.state.wait(state); - } + sys_usbd.todo("sys_usbd_receive_event(handle=0x%x, arg1=*0x%x, arg2=*0x%x, arg3=*0x%x)", handle, arg1, arg2, arg3); ppu.check_state(); *arg1 = ppu.gpr[4]; @@ -1377,7 +195,7 @@ error_code sys_usbd_transfer_data(ppu_thread& ppu, u32 handle, u32 id_pipe, vm:: { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_transfer_data(handle=0x%x, id_pipe=0x%x, buf=*0x%x, buf_length=0x%x, request=*0x%x, type=0x%x)", handle, id_pipe, buf, buf_size, request, type_transfer); + sys_usbd.todo("sys_usbd_transfer_data(handle=0x%x, id_pipe=0x%x, buf=*0x%x, buf_length=0x%x, request=*0x%x, type=0x%x)", handle, id_pipe, buf, buf_size, request, type_transfer); if (sys_usbd.trace && request) { @@ -1387,76 +205,8 @@ error_code sys_usbd_transfer_data(ppu_thread& ppu, u32 handle, u32 id_pipe, vm:: sys_usbd.trace("Control sent:\n%s", fmt::buf_to_hexstring(buf.get_ptr(), buf_size)); } - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.is_pipe(id_pipe)) - { - return CELL_EINVAL; - } - - const auto& pipe = usbh.get_pipe(id_pipe); - auto&& [transfer_id, transfer] = usbh.get_free_transfer(); - - transfer.assigned_number = pipe.device->assigned_number; - - // Default endpoint is control endpoint - if (pipe.endpoint == 0) - { - if (!request) - { - sys_usbd.error("Tried to use control pipe without proper request pointer"); - return CELL_EINVAL; - } - - // Claiming interface - switch (request->bmRequestType) - { - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE: - { - switch (request->bRequest) - { - case LIBUSB_REQUEST_SET_CONFIGURATION: - { - pipe.device->set_configuration(static_cast(+request->wValue)); - pipe.device->set_interface(0); - break; - } - default: break; - } - break; - } - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE: - { - if (!buf) - { - sys_usbd.error("Invalid buffer for control_transfer"); - return CELL_EFAULT; - } - break; - } - default: break; - } - - pipe.device->control_transfer(request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength, buf_size, buf.get_ptr(), &transfer); - } - else - { - // If output endpoint - if (!(pipe.endpoint & 0x80)) - sys_usbd.trace("Write Int(s: %d):\n%s", buf_size, fmt::buf_to_hexstring(buf.get_ptr(), buf_size)); - - pipe.device->interrupt_transfer(buf_size, buf.get_ptr(), pipe.endpoint, &transfer); - } - - if (transfer.fake) - { - usbh.push_fake_transfer(&transfer); - } - // returns an identifier specific to the transfer - return not_an_error(transfer_id); + return CELL_OK; } error_code sys_usbd_isochronous_transfer_data(ppu_thread& ppu, u32 handle, u32 id_pipe, vm::ptr iso_request) @@ -1465,40 +215,18 @@ error_code sys_usbd_isochronous_transfer_data(ppu_thread& ppu, u32 handle, u32 i sys_usbd.todo("sys_usbd_isochronous_transfer_data(handle=0x%x, id_pipe=0x%x, iso_request=*0x%x)", handle, id_pipe, iso_request); - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.is_pipe(id_pipe)) - { - return CELL_EINVAL; - } - - const auto& pipe = usbh.get_pipe(id_pipe); - auto&& [transfer_id, transfer] = usbh.get_free_transfer(); - - pipe.device->isochronous_transfer(&transfer); - // returns an identifier specific to the transfer - return not_an_error(transfer_id); + return CELL_OK; } error_code sys_usbd_get_transfer_status(ppu_thread& ppu, u32 handle, u32 id_transfer, u32 unk1, vm::ptr result, vm::ptr count) { ppu.state += cpu_flag::wait; - sys_usbd.trace("sys_usbd_get_transfer_status(handle=0x%x, id_transfer=0x%x, unk1=0x%x, result=*0x%x, count=*0x%x)", handle, id_transfer, unk1, result, count); - - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init) - return CELL_EINVAL; + sys_usbd.todo("sys_usbd_get_transfer_status(handle=0x%x, id_transfer=0x%x, unk1=0x%x, result=*0x%x, count=*0x%x)", handle, id_transfer, unk1, result, count); - const auto status = usbh.get_transfer_status(id_transfer); - *result = status.first; - *count = status.second; + *result = 0; + *count = 0; return CELL_OK; } @@ -1509,17 +237,7 @@ error_code sys_usbd_get_isochronous_transfer_status(ppu_thread& ppu, u32 handle, sys_usbd.todo("sys_usbd_get_isochronous_transfer_status(handle=0x%x, id_transfer=0x%x, unk1=0x%x, request=*0x%x, result=*0x%x)", handle, id_transfer, unk1, request, result); - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init) - return CELL_EINVAL; - - const auto status = usbh.get_isochronous_transfer_status(id_transfer); - - *result = status.first; - *request = status.second; + *result = 0; return CELL_OK; } @@ -1528,16 +246,7 @@ error_code sys_usbd_get_device_location(ppu_thread& ppu, u32 handle, u32 device_ { ppu.state += cpu_flag::wait; - sys_usbd.notice("sys_usbd_get_device_location(handle=0x%x, device_handle=0x%x, location=*0x%x)", handle, device_handle, location); - - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init || !usbh.handled_devices.count(device_handle)) - return CELL_EINVAL; - - usbh.handled_devices[device_handle].second->get_location(location.get_ptr()); + sys_usbd.todo("sys_usbd_get_device_location(handle=0x%x, device_handle=0x%x, location=*0x%x)", handle, device_handle, location); return CELL_OK; } @@ -1554,16 +263,7 @@ error_code sys_usbd_event_port_send(ppu_thread& ppu, u32 handle, u64 arg1, u64 a { ppu.state += cpu_flag::wait; - sys_usbd.warning("sys_usbd_event_port_send(handle=0x%x, arg1=0x%x, arg2=0x%x, arg3=0x%x)", handle, arg1, arg2, arg3); - - auto& usbh = g_fxo->get>(); - - std::lock_guard lock(usbh.mutex); - - if (!usbh.is_init) - return CELL_EINVAL; - - usbh.add_event(arg1, arg2, arg3); + sys_usbd.todo("sys_usbd_event_port_send(handle=0x%x, arg1=0x%x, arg2=0x%x, arg3=0x%x)", handle, arg1, arg2, arg3); return CELL_OK; } @@ -1591,3 +291,11 @@ error_code sys_usbd_get_device_speed(ppu_thread& ppu) sys_usbd.todo("sys_usbd_get_device_speed()"); return CELL_OK; } + +void connect_usb_controller(u8 index, input::product_type) +{ +} + +void handle_hotplug_event(bool connected) +{ +} diff --git a/rpcs3/Emu/Io/Buzz.cpp b/rpcs3/Emu/Io/Buzz.cpp deleted file mode 100644 index 2d75495743..0000000000 --- a/rpcs3/Emu/Io/Buzz.cpp +++ /dev/null @@ -1,206 +0,0 @@ -// Buzz! buzzer emulator - -#include "stdafx.h" -#include "Buzz.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/Io/buzz_config.h" -#include "Emu/system_config.h" -#include "Input/pad_thread.h" - -LOG_CHANNEL(buzz_log, "BUZZ"); - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](buzz_btn value) - { - switch (value) - { - case buzz_btn::red: return "Red"; - case buzz_btn::yellow: return "Yellow"; - case buzz_btn::green: return "Green"; - case buzz_btn::orange: return "Orange"; - case buzz_btn::blue: return "Blue"; - case buzz_btn::count: return "Count"; - } - - return unknown; - }); -} - -usb_device_buzz::usb_device_buzz(u32 first_controller, u32 last_controller, const std::array& location) - : usb_device_emulated(location), m_first_controller(first_controller), m_last_controller(last_controller) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0200, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x08, - .idVendor = 0x054c, - .idProduct = 0x0002, - .bcdDevice = 0x05a1, - .iManufacturer = 0x02, - .iProduct = 0x01, - .iSerialNumber = 0x00, - .bNumConfigurations = 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 0x0022, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0x80, - .bMaxPower = 0x32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x01, - .bInterfaceClass = 0x03, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, - .iInterface = 0x00})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, - UsbDeviceHID{ - .bcdHID = 0x0111, - .bCountryCode = 0x33, - .bNumDescriptors = 0x01, - .bDescriptorType = 0x22, - .wDescriptorLength = 0x004e})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x81, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0008, - .bInterval = 0x0A})); - - add_string("Logitech Buzz(tm) Controller V1"); - add_string("Logitech"); -} - -usb_device_buzz::~usb_device_buzz() -{ -} - -std::shared_ptr usb_device_buzz::make_instance(u32 controller_index, const std::array& location) -{ - if (controller_index == 0) - { - return std::make_shared(0, 3, location); - } - - // The current buzz emulation piggybacks on the pad input. - // Since there can only be 7 pads connected on a PS3 the 8th player is currently not supported - return std::make_shared(4, 6, location); -} - -u16 usb_device_buzz::get_num_emu_devices() -{ - return static_cast(g_cfg.io.buzz.get()); -} - -void usb_device_buzz::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - // Control transfers are nearly instant - transfer->expected_time = get_timestamp() + 100; - - switch (bmRequestType) - { - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE: // 0x21 - switch (bRequest) - { - case 0x09: // SET_REPORT - ensure(buf_size > 4); - buzz_log.trace("Leds: %s/%s/%s/%s", - buf[1] == 0xff ? "ON" : "OFF", - buf[2] == 0xff ? "ON" : "OFF", - buf[3] == 0xff ? "ON" : "OFF", - buf[4] == 0xff ? "ON" : "OFF"); - break; - default: - buzz_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest); - break; - } - break; - default: - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - break; - } -} - -extern bool is_input_allowed(); - -void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer) -{ - const u8 max_index = 2 + (4 + 5 * m_last_controller) / 8; - ensure(buf_size > max_index); - - transfer->fake = true; - transfer->expected_count = 5; - 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); - - // https://gist.github.com/Lewiscowles1986/eef220dac6f0549e4702393a7b9351f6 - buf[0] = 0x7f; - buf[1] = 0x7f; - buf[2] = 0x00; - buf[3] = 0x00; - buf[4] = 0xf0; - - if (!is_input_allowed()) - { - return; - } - - std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_pad_thread(); - const auto& pads = handler->GetPads(); - ensure(pads.size() > m_last_controller); - ensure(g_cfg_buzz.players.size() > m_last_controller); - - for (u32 i = m_first_controller, index = 0; i <= m_last_controller; i++, index++) - { - const auto& pad = pads[i]; - - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) - { - continue; - } - - const auto& cfg = g_cfg_buzz.players[i]; - cfg->handle_input(pad, true, [&buf, &index](buzz_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; - - switch (btn) - { - case buzz_btn::red: - buf[2 + (0 + 5 * index) / 8] |= 1 << ((0 + 5 * index) % 8); // Red - break; - case buzz_btn::yellow: - buf[2 + (1 + 5 * index) / 8] |= 1 << ((1 + 5 * index) % 8); // Yellow - break; - case buzz_btn::green: - buf[2 + (2 + 5 * index) / 8] |= 1 << ((2 + 5 * index) % 8); // Green - break; - case buzz_btn::orange: - buf[2 + (3 + 5 * index) / 8] |= 1 << ((3 + 5 * index) % 8); // Orange - break; - case buzz_btn::blue: - buf[2 + (4 + 5 * index) / 8] |= 1 << ((4 + 5 * index) % 8); // Blue - break; - case buzz_btn::count: - break; - } - }); - } -} diff --git a/rpcs3/Emu/Io/Buzz.h b/rpcs3/Emu/Io/Buzz.h deleted file mode 100644 index e8aafc0e35..0000000000 --- a/rpcs3/Emu/Io/Buzz.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_buzz : public usb_device_emulated -{ -public: - usb_device_buzz(u32 first_controller, u32 last_controller, const std::array& location); - ~usb_device_buzz(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - -private: - u32 m_first_controller; - u32 m_last_controller; -}; diff --git a/rpcs3/Emu/Io/Dimensions.cpp b/rpcs3/Emu/Io/Dimensions.cpp deleted file mode 100644 index 158f310bdb..0000000000 --- a/rpcs3/Emu/Io/Dimensions.cpp +++ /dev/null @@ -1,711 +0,0 @@ -#include "stdafx.h" -#include "Dimensions.h" - -#include - -#include "Emu/Cell/lv2/sys_usbd.h" - -LOG_CHANNEL(dimensions_log, "dimensions"); - -dimensions_toypad g_dimensionstoypad; - -static constexpr std::array COMMAND_KEY = {0x55, 0xFE, 0xF6, 0xB0, 0x62, 0xBF, 0x0B, 0x41, - 0xC9, 0xB3, 0x7C, 0xB4, 0x97, 0x3E, 0x29, 0x7B}; - -static constexpr std::array CHAR_CONSTANT = {0xB7, 0xD5, 0xD7, 0xE6, 0xE7, 0xBA, 0x3C, - 0xA8, 0xD8, 0x75, 0x47, 0x68, 0xCF, 0x23, 0xE9, 0xFE, 0xAA}; - -static constexpr std::array PWD_CONSTANT = {0x28, 0x63, 0x29, 0x20, 0x43, 0x6F, 0x70, 0x79, - 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x4C, 0x45, 0x47, 0x4F, 0x20, 0x32, 0x30, 0x31, 0x34, 0xAA, 0xAA}; - -void dimensions_figure::save() -{ - if (!dim_file) - { - dimensions_log.error("Tried to save infinity figure to file but no infinity figure is active!"); - return; - } - dim_file.seek(0, fs::seek_set); - dim_file.write(data.data(), 0x2D * 0x04); -} - -u8 dimensions_toypad::generate_checksum(const std::array& data, u32 num_of_bytes) -{ - int checksum = 0; - ensure(num_of_bytes <= data.size()); - for (u8 i = 0; i < num_of_bytes; i++) - { - checksum += data[i]; - } - return (checksum & 0xFF); -} - -void dimensions_toypad::get_blank_response(u8 type, u8 sequence, std::array& reply_buf) -{ - reply_buf[0] = 0x55; - reply_buf[1] = type; - reply_buf[2] = sequence; - reply_buf[3] = generate_checksum(reply_buf, 3); -} - -void dimensions_toypad::generate_random_number(const u8* buf, u8 sequence, std::array& reply_buf) -{ - // Decrypt payload into an 8 byte array - const std::array value = decrypt(buf, std::nullopt); - // Seed is the first 4 bytes (little endian) of the decrypted payload - const u32 seed = read_from_ptr>(value); - // Confirmation is the second 4 bytes (big endian) of the decrypted payload - const u32 conf = read_from_ptr>(value, 4); - // Initialize rng using the seed from decrypted payload - initialize_rng(seed); - std::array value_to_encrypt = {}; - // Encrypt 8 bytes, first 4 bytes is the decrypted confirmation from payload, 2nd 4 bytes are blank - write_to_ptr>(value_to_encrypt, conf); - const std::array encrypted = encrypt(value_to_encrypt.data(), std::nullopt); - reply_buf[0] = 0x55; - reply_buf[1] = 0x09; - reply_buf[2] = sequence; - // Copy encrypted value to response data - std::memcpy(&reply_buf[3], encrypted.data(), encrypted.size()); - reply_buf[11] = generate_checksum(reply_buf, 11); -} - -void dimensions_toypad::initialize_rng(u32 seed) -{ - m_random_a = 0xF1EA5EED; - m_random_b = seed; - m_random_c = seed; - m_random_d = seed; - - for (int i = 0; i < 42; i++) - { - get_next(); - } -} - -u32 dimensions_toypad::get_next() -{ - const u32 e = m_random_a - std::rotl(m_random_b, 21); - m_random_a = m_random_b ^ std::rotl(m_random_c, 19); - m_random_b = m_random_c + std::rotl(m_random_d, 6); - m_random_c = m_random_d + e; - m_random_d = e + m_random_a; - return m_random_d; -} - -std::array dimensions_toypad::decrypt(const u8* buf, std::optional> key) -{ - // Value to decrypt is separated in to two little endian 32 bit unsigned integers - u32 data_one = read_from_ptr>(buf); - u32 data_two = read_from_ptr>(buf, 4); - - // Use the key as 4 32 bit little endian unsigned integers - u32 key_one; - u32 key_two; - u32 key_three; - u32 key_four; - - if (key) - { - key_one = read_from_ptr>(key.value()); - key_two = read_from_ptr>(key.value(), 4); - key_three = read_from_ptr>(key.value(), 8); - key_four = read_from_ptr>(key.value(), 12); - } - else - { - key_one = read_from_ptr>(COMMAND_KEY); - key_two = read_from_ptr>(COMMAND_KEY, 4); - key_three = read_from_ptr>(COMMAND_KEY, 8); - key_four = read_from_ptr>(COMMAND_KEY, 12); - } - - u32 sum = 0xC6EF3720; - constexpr u32 delta = 0x9E3779B9; - - for (int i = 0; i < 32; i++) - { - data_two -= (((data_one << 4) + key_three) ^ (data_one + sum) ^ ((data_one >> 5) + key_four)); - data_one -= (((data_two << 4) + key_one) ^ (data_two + sum) ^ ((data_two >> 5) + key_two)); - sum -= delta; - } - - ensure(sum == 0, "Decryption failed, sum inequal to 0"); - - std::array decrypted = {u8(data_one & 0xFF), u8((data_one >> 8) & 0xFF), - u8((data_one >> 16) & 0xFF), u8((data_one >> 24) & 0xFF), - u8(data_two & 0xFF), u8((data_two >> 8) & 0xFF), - u8((data_two >> 16) & 0xFF), u8((data_two >> 24) & 0xFF)}; - return decrypted; -} - -std::array dimensions_toypad::encrypt(const u8* buf, std::optional> key) -{ - // Value to encrypt is separated in to two little endian 32 bit unsigned integers - - u32 data_one = read_from_ptr>(buf); - u32 data_two = read_from_ptr>(buf, 4); - - // Use the key as 4 32 bit little endian unsigned integers - u32 key_one; - u32 key_two; - u32 key_three; - u32 key_four; - - if (key) - { - key_one = read_from_ptr>(key.value()); - key_two = read_from_ptr>(key.value(), 4); - key_three = read_from_ptr>(key.value(), 8); - key_four = read_from_ptr>(key.value(), 12); - } - else - { - key_one = read_from_ptr>(COMMAND_KEY); - key_two = read_from_ptr>(COMMAND_KEY, 4); - key_three = read_from_ptr>(COMMAND_KEY, 8); - key_four = read_from_ptr>(COMMAND_KEY, 12); - } - - u32 sum = 0; - constexpr u32 delta = 0x9E3779B9; - - for (int i = 0; i < 32; i++) - { - sum += delta; - data_one += (((data_two << 4) + key_one) ^ (data_two + sum) ^ ((data_two >> 5) + key_two)); - data_two += (((data_one << 4) + key_three) ^ (data_one + sum) ^ ((data_one >> 5) + key_four)); - } - - ensure(sum == 0xC6EF3720, "Encryption failed, sum inequal to 0xC6EF3720"); - - std::array encrypted = {u8(data_one & 0xFF), u8((data_one >> 8) & 0xFF), - u8((data_one >> 16) & 0xFF), u8((data_one >> 24) & 0xFF), - u8(data_two & 0xFF), u8((data_two >> 8) & 0xFF), - u8((data_two >> 16) & 0xFF), u8((data_two >> 24) & 0xFF)}; - return encrypted; -} - -std::array dimensions_toypad::generate_figure_key(const std::array& buf) -{ - std::array uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]}; - - std::array figure_key = {}; - - write_to_ptr>(figure_key, scramble(uid, 3)); - write_to_ptr>(figure_key, 4, scramble(uid, 4)); - write_to_ptr>(figure_key, 8, scramble(uid, 5)); - write_to_ptr>(figure_key, 12, scramble(uid, 6)); - - return figure_key; -} - -u32 dimensions_toypad::scramble(const std::array& uid, u8 count) -{ - std::vector to_scramble; - to_scramble.reserve(uid.size() + CHAR_CONSTANT.size()); - for (u8 x : uid) - { - to_scramble.push_back(x); - } - for (u8 c : CHAR_CONSTANT) - { - to_scramble.push_back(c); - } - ::at32(to_scramble, count * 4 - 1) = 0xaa; - - return read_from_ptr>(dimensions_randomize(to_scramble, count).data()); -} - -std::array dimensions_toypad::dimensions_randomize(const std::vector& key, u8 count) -{ - u32 scrambled = 0; - for (u8 i = 0; i < count; i++) - { - const u32 v4 = std::rotr(scrambled, 25); - const u32 v5 = std::rotr(scrambled, 10); - const u32 b = read_from_ptr>(key, i * 4); - scrambled = b + v4 + v5 - scrambled; - } - return {u8(scrambled & 0xFF), u8(scrambled >> 8 & 0xFF), u8(scrambled >> 16 & 0xFF), u8(scrambled >> 24 & 0xFF)}; -} - -u32 dimensions_toypad::get_figure_id(const std::array& buf) -{ - const std::array figure_key = generate_figure_key(buf); - - const std::array decrypted = decrypt(&buf[36 * 4], figure_key); - - const u32 fig_num = read_from_ptr>(decrypted); - // Characters have their model number encrypted in page 36 - if (fig_num < 1000) - { - return fig_num; - } - // Vehicles/Gadgets have their model number written as little endian in page 36 - return read_from_ptr>(buf, 36 * 4); -} - -dimensions_figure& dimensions_toypad::get_figure_by_index(u8 index) -{ - return ::at32(m_figures, index); -} - -void dimensions_toypad::random_uid(u8* uid_buffer) -{ - uid_buffer[0] = 0x04; - uid_buffer[7] = 0x80; - - for (u8 i = 1; i < 7; i++) - { - u8 random = rand() % 255; - uid_buffer[i] = random; - } -} - -void dimensions_toypad::get_challenge_response(const u8* buf, u8 sequence, std::array& reply_buf) -{ - // Decrypt payload into an 8 byte array - const std::array value = decrypt(buf, std::nullopt); - // Confirmation is the first 4 bytes of the decrypted payload - const u32 conf = read_from_ptr>(value); - // Generate next random number based on RNG - const u32 next_random = get_next(); - std::array value_to_encrypt = {}; - // Encrypt an 8 byte array, first 4 bytes are the next random number (little endian) - // followed by the confirmation from the decrypted payload - write_to_ptr>(value_to_encrypt, next_random); - write_to_ptr>(value_to_encrypt, 4, conf); - const std::array encrypted = encrypt(value_to_encrypt.data(), std::nullopt); - reply_buf[0] = 0x55; - reply_buf[1] = 0x09; - reply_buf[2] = sequence; - // Copy encrypted value to response data - std::memcpy(&reply_buf[3], encrypted.data(), encrypted.size()); - reply_buf[11] = generate_checksum(reply_buf, 11); -} - -void dimensions_toypad::query_block(u8 index, u8 page, std::array& reply_buf, u8 sequence) -{ - std::lock_guard lock(m_dimensions_mutex); - - reply_buf[0] = 0x55; - reply_buf[1] = 0x12; - reply_buf[2] = sequence; - reply_buf[3] = 0x00; - - // Index from game begins at 1 rather than 0, so minus 1 here - if (const u8 figure_index = index - 1; figure_index < dimensions_figure_count) - { - const dimensions_figure& figure = get_figure_by_index(figure_index); - - // Query 4 pages of 4 bytes from the figure, copy this to the response - if (figure.index != 255 && (4 * page) < ((0x2D * 4) - 16)) - { - std::memcpy(&reply_buf[4], figure.data.data() + (4 * page), 16); - } - } - reply_buf[20] = generate_checksum(reply_buf, 20); -} - -void dimensions_toypad::write_block(u8 index, u8 page, const u8* to_write_buf, std::array& reply_buf, u8 sequence) -{ - std::lock_guard lock(m_dimensions_mutex); - - reply_buf[0] = 0x55; - reply_buf[1] = 0x02; - reply_buf[2] = sequence; - reply_buf[3] = 0x00; - - // Index from game begins at 1 rather than 0, so minus 1 here - if (const u8 figure_index = index - 1; figure_index < dimensions_figure_count) - { - dimensions_figure& figure = get_figure_by_index(figure_index); - - // Copy 4 bytes to the page on the figure requested by the game - if (figure.index != 255 && page < 0x2D) - { - // Id is written to page 36 - if (page == 36) - { - figure.id = read_from_ptr>(to_write_buf); - } - std::memcpy(figure.data.data() + (page * 4), to_write_buf, 4); - figure.save(); - } - } - reply_buf[4] = generate_checksum(reply_buf, 4); -} - -void dimensions_toypad::get_model(const u8* buf, u8 sequence, std::array& reply_buf) -{ - // Decrypt payload to 8 byte array, byte 1 is the index, 4-7 are the confirmation - const std::array value = decrypt(buf, std::nullopt); - const u8 index = value[0]; - const u32 conf = read_from_ptr>(value, 4); - std::array value_to_encrypt = {}; - // Response is the figure's id (little endian) followed by the confirmation from payload - // Index from game begins at 1 rather than 0, so minus 1 here - if (const u8 figure_index = index - 1; figure_index < dimensions_figure_count) - { - const dimensions_figure& figure = get_figure_by_index(figure_index); - write_to_ptr>(value_to_encrypt, figure.id); - } - write_to_ptr>(value_to_encrypt, 4, conf); - const std::array encrypted = encrypt(value_to_encrypt.data(), std::nullopt); - reply_buf[0] = 0x55; - reply_buf[1] = 0x0a; - reply_buf[2] = sequence; - reply_buf[3] = 0x00; - // Copy encrypted message to response - std::memcpy(&reply_buf[4], encrypted.data(), encrypted.size()); - reply_buf[12] = generate_checksum(reply_buf, 12); -} - -u32 dimensions_toypad::load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index, bool lock) -{ - if (lock) - { - m_dimensions_mutex.lock(); - } - - const u32 id = get_figure_id(buf); - - dimensions_figure& figure = get_figure_by_index(index); - figure.dim_file = std::move(in_file); - figure.id = id; - figure.pad = pad; - figure.index = index + 1; - std::memcpy(figure.data.data(), buf.data(), buf.size()); - // When a figure is added to the toypad, respond to the game with the pad they were added to, their index, - // the direction (0x00 in byte 6 for added) and their UID - std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00, - buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]}; - figure_change_response[13] = generate_checksum(figure_change_response, 13); - m_figure_added_removed_responses.push(std::move(figure_change_response)); - - if (lock) - { - m_dimensions_mutex.unlock(); - } - return id; -} - -bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool full_remove, bool lock) -{ - dimensions_figure& figure = get_figure_by_index(index); - if (figure.index == 255) - { - return false; - } - - if (lock) - { - m_dimensions_mutex.lock(); - } - - // When a figure is removed from the toypad, respond to the game with the pad they were removed from, their index, - // the direction (0x01 in byte 6 for removed) and their UID - if (full_remove) - { - std::array figure_change_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01, - figure.data[0], figure.data[1], figure.data[2], - figure.data[4], figure.data[5], figure.data[6], figure.data[7]}; - figure_change_response[13] = generate_checksum(figure_change_response, 13); - m_figure_added_removed_responses.push(std::move(figure_change_response)); - figure.save(); - figure.dim_file.close(); - } - - figure.index = 255; - figure.pad = 255; - figure.id = 0; - - if (lock) - { - m_dimensions_mutex.unlock(); - } - return true; -} - -bool dimensions_toypad::temp_remove(u8 index) -{ - std::lock_guard lock(m_dimensions_mutex); - - const dimensions_figure& figure = get_figure_by_index(index); - if (figure.index == 255) - return false; - - // Send a response to the game that the figure has been "Picked up" from existing slot, - // until either the movement is cancelled, or user chooses a space to move to - std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x01, - figure.data[0], figure.data[1], figure.data[2], - figure.data[4], figure.data[5], figure.data[6], figure.data[7]}; - - figure_change_response[13] = generate_checksum(figure_change_response, 13); - m_figure_added_removed_responses.push(std::move(figure_change_response)); - - return true; -} - -bool dimensions_toypad::cancel_remove(u8 index) -{ - std::lock_guard lock(m_dimensions_mutex); - - dimensions_figure& figure = get_figure_by_index(index); - if (figure.index == 255) - return false; - - // Cancel the previous movement of the figure - std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00, - figure.data[0], figure.data[1], figure.data[2], - figure.data[4], figure.data[5], figure.data[6], figure.data[7]}; - - figure_change_response[13] = generate_checksum(figure_change_response, 13); - m_figure_added_removed_responses.push(std::move(figure_change_response)); - - return true; -} - -bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index) -{ - if (old_index == index) - { - // Don't bother removing and loading again, just send response to the game - cancel_remove(index); - return true; - } - - std::lock_guard lock(m_dimensions_mutex); - - // When moving figures between spaces on the toypad, remove any figure from the space they are moving to, - // then remove them from their current space, then load them to the space they are moving to - remove_figure(pad, index, true, false); - - dimensions_figure& figure = get_figure_by_index(old_index); - const std::array data = figure.data; - fs::file in_file = std::move(figure.dim_file); - - remove_figure(old_pad, old_index, false, false); - - load_figure(data, std::move(in_file), pad, index, false); - - return true; -} - -bool dimensions_toypad::create_blank_character(std::array& buf, u16 id) -{ - random_uid(buf.data()); - buf[3] = id & 0xFF; - - // Only characters are created with their ID encrypted and stored in pages 36 and 37, - // as well as a password stored in page 43. Blank tags have their information populated - // by the game when it calls the write_block command. - if (id != 0) - { - // LEGO Dimensions figures use NTAG213 tag types, and the UID for these is stored in - // bytes 0, 1, 2, 4, 5, 6 and 7 (out of 180 bytes) - std::array uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]}; - const std::array figure_key = generate_figure_key(buf); - - std::array value_to_encrypt = {}; - write_to_ptr>(value_to_encrypt, id); - write_to_ptr>(value_to_encrypt, 4, id); - - std::array encrypted = encrypt(value_to_encrypt.data(), figure_key); - - std::memcpy(&buf[36 * 4], &encrypted[0], 4); - std::memcpy(&buf[37 * 4], &encrypted[4], 4); - - std::memcpy(&buf[43 * 4], pwd_generate(uid).data(), 4); - } - else - { - // Page 38 is used as verification for blank tags - write_to_ptr>(buf.data(), 38 * 4, 1); - } - - return true; -} - -std::array dimensions_toypad::pwd_generate(const std::array& uid) -{ - std::vector pwd_calc = {PWD_CONSTANT.begin(), PWD_CONSTANT.end() - 1}; - for (u8 i = 0; i < uid.size(); i++) - { - pwd_calc.insert(pwd_calc.begin() + i, uid[i]); - } - - return dimensions_randomize(pwd_calc, 8); -} - -std::optional> dimensions_toypad::pop_added_removed_response() -{ - std::lock_guard lock(m_dimensions_mutex); - - if (m_figure_added_removed_responses.empty()) - { - return std::nullopt; - } - - std::array response = m_figure_added_removed_responses.front(); - m_figure_added_removed_responses.pop(); - return response; -} - -usb_device_dimensions::usb_device_dimensions(const std::array& location) - : usb_device_emulated(location) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x200, 0x0, 0x0, 0x0, 0x20, 0x0E6F, 0x0241, 0x200, 0x1, 0x2, 0x3, 0x1}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x29, 0x1, 0x1, 0x0, 0x80, 0xFA})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 0x001d})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x20, 0x1})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x01, 0x03, 0x20, 0x1})); -} - -usb_device_dimensions::~usb_device_dimensions() -{ -} - -std::shared_ptr usb_device_dimensions::make_instance(u32, const std::array& location) -{ - return std::make_shared(location); -} - -u16 usb_device_dimensions::get_num_emu_devices() -{ - return 1; -} - -void usb_device_dimensions::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); -} - -void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) -{ - ensure(buf_size == 0x20); - - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - - switch (endpoint) - { - case 0x81: - { - // Read Endpoint, if a request has not been sent via the write endpoint, set expected result as - // EHCI_CC_HALTED so the game doesn't report the Toypad as being disconnected. - std::lock_guard lock(m_query_mutex); - std::optional> response = g_dimensionstoypad.pop_added_removed_response(); - if (response) - { - std::memcpy(buf, response.value().data(), 0x20); - } - else if (!m_queries.empty()) - { - std::memcpy(buf, m_queries.front().data(), 0x20); - m_queries.pop(); - } - else - { - transfer->expected_count = 0; - transfer->expected_result = EHCI_CC_HALTED; - } - break; - } - case 0x01: - { - // Write endpoint, similar structure of request to the Infinity Base with a command for byte 3, - // sequence for byte 4, the payload after that, then a checksum for the final byte. - - const u8 command = buf[2]; - const u8 sequence = buf[3]; - - transfer->expected_time = get_timestamp() + 100; - std::array q_result{}; - - switch (command) - { - case 0xB0: // Wake - { - // Consistent device response to the wake command - q_result = {0x55, 0x0e, 0x01, 0x28, 0x63, 0x29, - 0x20, 0x4c, 0x45, 0x47, 0x4f, 0x20, - 0x32, 0x30, 0x31, 0x34, 0x46}; - break; - } - case 0xB1: // Seed - { - // Initialise a random number generator using the seed provided - g_dimensionstoypad.generate_random_number(&buf[4], sequence, q_result); - break; - } - case 0xB3: // Challenge - { - // Get the next number in the sequence based on the RNG from 0xB1 command - g_dimensionstoypad.get_challenge_response(&buf[4], sequence, q_result); - break; - } - case 0xC0: // Color - case 0xC1: // Get Pad Color - case 0xC2: // Fade - case 0xC3: // Flash - case 0xC4: // Fade Random - case 0xC6: // Fade All - case 0xC7: // Flash All - case 0xC8: // Color All - { - // Send a blank response to acknowledge color has been sent to toypad - g_dimensionstoypad.get_blank_response(0x01, sequence, q_result); - break; - } - case 0xD2: // Read - { - // Read 4 pages from the figure at index (buf[4]), starting with page buf[5] - g_dimensionstoypad.query_block(buf[4], buf[5], q_result, sequence); - break; - } - case 0xD3: // Write - { - // Write 4 bytes to page buf[5] to the figure at index buf[4] - g_dimensionstoypad.write_block(buf[4], buf[5], &buf[6], q_result, sequence); - break; - } - case 0xD4: // Model - { - // Get the model id of the figure at index buf[4] - g_dimensionstoypad.get_model(&buf[4], sequence, q_result); - break; - } - case 0xD0: // Tag List - case 0xE1: // PWD - case 0xE5: // Active - case 0xFF: // LEDS Query - { - // Further investigation required - dimensions_log.error("Unimplemented LD Function: 0x%x", command); - dimensions_log.error("Request: %s", fmt::buf_to_hexstring(buf, buf_size)); - break; - } - default: - { - dimensions_log.error("Unknown LD Function: 0x%x", command); - dimensions_log.error("Request: %s", fmt::buf_to_hexstring(buf, buf_size)); - break; - } - } - std::lock_guard lock(m_query_mutex); - m_queries.push(q_result); - break; - } - default: - break; - } -} - -void usb_device_dimensions::isochronous_transfer(UsbTransfer* transfer) -{ - usb_device_emulated::isochronous_transfer(transfer); -} diff --git a/rpcs3/Emu/Io/Dimensions.h b/rpcs3/Emu/Io/Dimensions.h deleted file mode 100644 index 3ad359cbac..0000000000 --- a/rpcs3/Emu/Io/Dimensions.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" -#include "util/mutex.h" -#include -#include -#include - -static constexpr size_t dimensions_figure_count = 7; - -struct dimensions_figure -{ - fs::file dim_file; - std::array data{}; - u8 index = 255; - u8 pad = 255; - u32 id = 0; - void save(); -}; - -class dimensions_toypad -{ -public: - static void get_blank_response(u8 type, u8 sequence, std::array& reply_buf); - void generate_random_number(const u8* buf, u8 sequence, std::array& reply_buf); - void initialize_rng(u32 seed); - void get_challenge_response(const u8* buf, u8 sequence, std::array& reply_buf); - void query_block(u8 index, u8 page, std::array& reply_buf, u8 sequence); - void write_block(u8 index, u8 page, const u8* to_write_buf, std::array& reply_buf, u8 sequence); - void get_model(const u8* buf, u8 sequence, std::array& reply_buf); - std::optional> pop_added_removed_response(); - - bool remove_figure(u8 pad, u8 index, bool full_remove, bool lock); - bool temp_remove(u8 index); - bool cancel_remove(u8 index); - u32 load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index, bool lock); - bool move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index); - static bool create_blank_character(std::array& buf, u16 id); - -protected: - shared_mutex m_dimensions_mutex; - std::array m_figures{}; - -private: - static void random_uid(u8* uid_buffer); - static u8 generate_checksum(const std::array& data, u32 num_of_bytes); - static std::array decrypt(const u8* buf, std::optional> key); - static std::array encrypt(const u8* buf, std::optional> key); - static std::array generate_figure_key(const std::array& buf); - static u32 scramble(const std::array& uid, u8 count); - static std::array pwd_generate(const std::array& uid); - static std::array dimensions_randomize(const std::vector& key, u8 count); - static u32 get_figure_id(const std::array& buf); - u32 get_next(); - dimensions_figure& get_figure_by_index(u8 index); - - u32 m_random_a{}; - u32 m_random_b{}; - u32 m_random_c{}; - u32 m_random_d{}; - - u8 m_figure_order = 0; - std::queue> m_figure_added_removed_responses; -}; - -extern dimensions_toypad g_dimensionstoypad; - -class usb_device_dimensions : public usb_device_emulated -{ -public: - usb_device_dimensions(const std::array& location); - ~usb_device_dimensions(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - void isochronous_transfer(UsbTransfer* transfer) override; - -protected: - shared_mutex m_query_mutex; - std::queue> m_queries; -}; diff --git a/rpcs3/Emu/Io/GHLtar.cpp b/rpcs3/Emu/Io/GHLtar.cpp deleted file mode 100644 index c01a70f3b4..0000000000 --- a/rpcs3/Emu/Io/GHLtar.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// Guitar Hero Live controller emulator - -#include "stdafx.h" -#include "GHLtar.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/Io/ghltar_config.h" -#include "Emu/system_config.h" -#include "Input/pad_thread.h" - -LOG_CHANNEL(ghltar_log, "GHLTAR"); - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](ghltar_btn value) - { - switch (value) - { - case ghltar_btn::w1: return "W1"; - case ghltar_btn::w2: return "W2"; - case ghltar_btn::w3: return "W3"; - case ghltar_btn::b1: return "B1"; - case ghltar_btn::b2: return "B2"; - case ghltar_btn::b3: return "B3"; - case ghltar_btn::start: return "Start"; - case ghltar_btn::hero_power: return "Hero Power"; - case ghltar_btn::ghtv: return "GHTV"; - case ghltar_btn::strum_down: return "Strum Down"; - case ghltar_btn::strum_up: return "Strum Up"; - case ghltar_btn::dpad_left: return "D-Pad Left"; - case ghltar_btn::dpad_right: return "D-Pad Right"; - case ghltar_btn::whammy: return "Whammy"; - case ghltar_btn::tilt: return "Tilt"; - case ghltar_btn::count: return "Count"; - } - - return unknown; - }); -} - -usb_device_ghltar::usb_device_ghltar(u32 controller_index, const std::array& location) - : usb_device_emulated(location), m_controller_index(controller_index) -{ - 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() -{ -} - -std::shared_ptr usb_device_ghltar::make_instance(u32 controller_index, const std::array& location) -{ - return std::make_shared(controller_index, location); -} - -u16 usb_device_ghltar::get_num_emu_devices() -{ - return static_cast(g_cfg.io.ghltar.get()); -} - -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: buf_size=0x%02X, Type=0x%02X, bRequest=0x%02X, bmRequestType=0x%02X", buf_size, (buf_size > 0) ? buf[0] : -1, bRequest, bmRequestType); - break; - } - break; - default: - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - break; - } -} - -extern bool is_input_allowed(); - -void usb_device_ghltar::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer) -{ - ensure(buf_size >= 27); - - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - // Interrupt transfers are slow(6ms, TODO accurate measurement) - // But make the emulated guitar reply in 1ms for better input behavior - transfer->expected_time = get_timestamp() + 1'000; - - 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 - - if (!is_input_allowed()) - { - return; - } - - std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_pad_thread(); - const auto& pad = ::at32(handler->GetPads(), m_controller_index); - - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) - { - return; - } - - const auto& cfg = ::at32(g_cfg_ghltar.players, m_controller_index); - cfg->handle_input(pad, true, [&buf](ghltar_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; - - switch (btn) - { - case ghltar_btn::w1: - buf[0] += 0x01; // W1 - break; - case ghltar_btn::b1: - buf[0] += 0x02; // B1 - break; - case ghltar_btn::b2: - buf[0] += 0x04; // B2 - break; - case ghltar_btn::b3: - buf[0] += 0x08; // B3 - break; - case ghltar_btn::w3: - buf[0] += 0x20; // W3 - break; - case ghltar_btn::w2: - buf[0] += 0x10; // W2 - break; - case ghltar_btn::strum_down: - buf[4] = 0xFF; // Strum Down - break; - case ghltar_btn::strum_up: - buf[4] = 0x00; // Strum Up - break; - case ghltar_btn::dpad_left: - buf[2] = 0x02; // Left D-Pad (Unused) - break; - case ghltar_btn::dpad_right: - buf[2] = 0x06; // Right D-Pad (Unused) - break; - case ghltar_btn::start: - buf[1] += 0x02; // Pause - break; - case ghltar_btn::hero_power: - buf[1] += 0x01; // Hero Power - break; - case ghltar_btn::ghtv: - buf[1] += 0x04; // GHTV Button - break; - case ghltar_btn::whammy: - buf[6] = ~(value) + 0x01; // Whammy - break; - case ghltar_btn::tilt: - buf[19] = static_cast(value); // Tilt - if (buf[19] >= 0xF0) - buf[5] = 0xFF; - else if (buf[19] <= 0x10) - buf[5] = 0x00; - break; - case ghltar_btn::count: - break; - } - }); -} diff --git a/rpcs3/Emu/Io/GHLtar.h b/rpcs3/Emu/Io/GHLtar.h deleted file mode 100644 index e36df36498..0000000000 --- a/rpcs3/Emu/Io/GHLtar.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_ghltar : public usb_device_emulated -{ -public: - usb_device_ghltar(u32 controller_index, const std::array& location); - ~usb_device_ghltar(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - -private: - u32 m_controller_index; -}; diff --git a/rpcs3/Emu/Io/GameTablet.cpp b/rpcs3/Emu/Io/GameTablet.cpp deleted file mode 100644 index f17a0980eb..0000000000 --- a/rpcs3/Emu/Io/GameTablet.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include "stdafx.h" -#include "GameTablet.h" -#include "MouseHandler.h" -#include "Emu/IdManager.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/system_config.h" -#include "Input/pad_thread.h" - -LOG_CHANNEL(gametablet_log); - -#pragma pack(push, 1) -struct GameTablet_data -{ - uint8_t btn_square : 1; - uint8_t btn_cross : 1; - uint8_t btn_circle : 1; - uint8_t btn_triangle : 1; - uint8_t : 4; - - uint8_t btn_select : 1; - uint8_t btn_start : 1; - uint8_t : 2; - uint8_t btn_ps : 1; - uint8_t : 3; - - uint8_t dpad; - uint8_t stick_lx; // 0x80 - uint8_t stick_ly; // 0x80 - uint8_t stick_rx; // 0x80 - uint8_t stick_ry; // 0x80 - - uint8_t : 8; - uint8_t : 8; - uint8_t : 8; - uint8_t : 8; - uint8_t pen; - uint8_t : 8; - uint8_t pressure; - uint8_t : 8; - uint8_t pos_x_hi; - uint8_t pos_y_hi; - uint8_t pos_x_lo; - uint8_t pos_y_lo; - - uint16_t accel_x; - uint16_t accel_y; - uint16_t accel_z; - uint16_t unk; // 0x0200 -}; -#pragma pack(pop) - -enum -{ - Dpad_North, - Dpad_NE, - Dpad_East, - Dpad_SE, - Dpad_South, - Dpad_SW, - Dpad_West, - Dpad_NW, - Dpad_None = 0x0f -}; - -usb_device_gametablet::usb_device_gametablet(u32 controller_index, const std::array& location) - : usb_device_emulated(location), m_controller_index(controller_index) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0200, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x08, - .idVendor = 0x20d6, - .idProduct = 0xcb17, - .bcdDevice = 0x0108, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x00, - .bNumConfigurations = 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 0x0029, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0x80, - .bMaxPower = 0x32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x02, - .bInterfaceClass = 0x03, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, - .iInterface = 0x00})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, - UsbDeviceHID{ - .bcdHID = 0x0110, - .bCountryCode = 0x00, - .bNumDescriptors = 0x01, - .bDescriptorType = 0x22, - .wDescriptorLength = 0x0089})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x83, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0040, - .bInterval = 0x0A})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x04, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0040, - .bInterval = 0x0A})); - - add_string("THQ Inc"); - add_string("THQ uDraw Game Tablet for PS3"); -} - -usb_device_gametablet::~usb_device_gametablet() -{ -} - -void usb_device_gametablet::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 100; - - // Control transfers are nearly instant - switch (bmRequestType) - { - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE: // 0x21 - switch (bRequest) - { - case 0x09: // SET_REPORT - ensure(buf_size > 2); - gametablet_log.trace("Leds: %s/%s/%s/%s", - buf[2] & 1 ? "ON" : "OFF", - buf[2] & 2 ? "ON" : "OFF", - buf[2] & 4 ? "ON" : "OFF", - buf[2] & 8 ? "ON" : "OFF"); - break; - default: - gametablet_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest); - break; - } - break; - default: - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - break; - } -} - -extern bool is_input_allowed(); - -void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer) -{ - ensure(buf_size >= sizeof(GameTablet_data)); - - transfer->fake = true; - transfer->expected_count = sizeof(GameTablet_data); - transfer->expected_result = HC_CC_NOERR; - // Interrupt transfers are slow (6ms, TODO accurate measurement) - transfer->expected_time = get_timestamp() + 6000; - - GameTablet_data gt{}; - - gt.dpad = Dpad_None; - gt.stick_lx = gt.stick_ly = gt.stick_rx = gt.stick_ry = 0x80; - gt.pressure = 0x72; - gt.pos_x_hi = gt.pos_y_hi = 0x0f; - gt.pos_x_lo = gt.pos_y_lo = 0xff; - gt.accel_x = gt.accel_y = gt.accel_z = gt.unk = 0x0200; - - if (!is_input_allowed()) - { - std::memcpy(buf, >, sizeof(GameTablet_data)); - return; - } - - if (g_cfg.io.mouse == mouse_handler::null) - { - gametablet_log.warning("GameTablet requires a Mouse Handler enabled"); - std::memcpy(buf, >, sizeof(GameTablet_data)); - return; - } - - bool up = false, right = false, down = false, left = false; - - { - std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_pad_thread(); - const auto& pads = gamepad_handler->GetPads(); - const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) - { - for (Button& button : pad->m_buttons) - { - if (!button.m_pressed) - { - continue; - } - - if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) - { - switch (button.m_outKeyCode) - { - case CELL_PAD_CTRL_SELECT: - gt.btn_select |= 1; - break; - case CELL_PAD_CTRL_START: - gt.btn_start |= 1; - break; - case CELL_PAD_CTRL_UP: - up = true; - break; - case CELL_PAD_CTRL_RIGHT: - right = true; - break; - case CELL_PAD_CTRL_DOWN: - down = true; - break; - case CELL_PAD_CTRL_LEFT: - left = true; - break; - default: - break; - } - } - else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) - { - switch (button.m_outKeyCode) - { - case CELL_PAD_CTRL_SQUARE: - gt.btn_square |= 1; - break; - case CELL_PAD_CTRL_CROSS: - gt.btn_cross |= 1; - break; - case CELL_PAD_CTRL_CIRCLE: - gt.btn_circle |= 1; - break; - case CELL_PAD_CTRL_TRIANGLE: - gt.btn_triangle |= 1; - break; - case CELL_PAD_CTRL_PS: - gt.btn_ps |= 1; - break; - default: - break; - } - } - } - } - } - - if (!up && !right && !down && !left) - gt.dpad = Dpad_None; - else if (up && !left && !right) - gt.dpad = Dpad_North; - else if (up && right) - gt.dpad = Dpad_NE; - else if (right && !up && !down) - gt.dpad = Dpad_East; - else if (down && right) - gt.dpad = Dpad_SE; - else if (down && !left && !right) - gt.dpad = Dpad_South; - else if (down && left) - gt.dpad = Dpad_SW; - else if (left && !up && !down) - gt.dpad = Dpad_West; - else if (up && left) - gt.dpad = Dpad_NW; - - auto& mouse_handler = g_fxo->get(); - std::lock_guard mouse_lock(mouse_handler.mutex); - - mouse_handler.Init(1); - - constexpr u8 mouse_index = 0; - if (mouse_index >= mouse_handler.GetMice().size()) - { - std::memcpy(buf, >, sizeof(GameTablet_data)); - return; - } - - const Mouse& mouse_data = ::at32(mouse_handler.GetMice(), mouse_index); - if (mouse_data.x_max <= 0 || mouse_data.y_max <= 0) - { - std::memcpy(buf, >, sizeof(GameTablet_data)); - return; - } - - static u8 noise_x = 0; // Toggle the LSB to simulate a noisy signal, Instant Artist dislikes a pen held perfectly still - static u8 noise_y = 0; - constexpr s32 tablet_max_x = 1920; - constexpr s32 tablet_max_y = 1080; - - const s32 tablet_x_pos = (mouse_data.x_pos * tablet_max_x / mouse_data.x_max) ^ noise_x; - const s32 tablet_y_pos = (mouse_data.y_pos * tablet_max_y / mouse_data.y_max) ^ noise_y; - noise_x ^= 0x1; - noise_y ^= 0x1; - - gt.pen = 0x40; - gt.pressure = mouse_data.buttons & CELL_MOUSE_BUTTON_1 ? 0xbb : 0x72; - gt.pos_x_hi = static_cast(tablet_x_pos / 0x100); - gt.pos_y_hi = static_cast(tablet_y_pos / 0x100); - gt.pos_x_lo = static_cast(tablet_x_pos % 0x100); - gt.pos_y_lo = static_cast(tablet_y_pos % 0x100); - - std::memcpy(buf, >, sizeof(GameTablet_data)); -} diff --git a/rpcs3/Emu/Io/GameTablet.h b/rpcs3/Emu/Io/GameTablet.h deleted file mode 100644 index 7fdbf8eaa6..0000000000 --- a/rpcs3/Emu/Io/GameTablet.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_gametablet : public usb_device_emulated -{ -public: - usb_device_gametablet(u32 controller_index, const std::array& location); - ~usb_device_gametablet(); - - 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; - -private: - u32 m_controller_index; -}; diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp deleted file mode 100644 index 5153f6f510..0000000000 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include "stdafx.h" -#include "GunCon3.h" -#include "MouseHandler.h" -#include "Emu/IdManager.h" -#include "Emu/Io/guncon3_config.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/system_config.h" -#include "Input/pad_thread.h" - -LOG_CHANNEL(guncon3_log); - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](guncon3_btn value) - { - switch (value) - { - case guncon3_btn::trigger: return "Trigger"; - case guncon3_btn::a1: return "A1"; - case guncon3_btn::a2: return "A2"; - case guncon3_btn::a3: return "A3"; - case guncon3_btn::b1: return "B1"; - case guncon3_btn::b2: return "B2"; - case guncon3_btn::b3: return "B3"; - case guncon3_btn::c1: return "C1"; - case guncon3_btn::c2: return "C2"; - case guncon3_btn::as_x: return "A-stick X-Axis"; - case guncon3_btn::as_y: return "A-stick Y-Axis"; - case guncon3_btn::bs_x: return "B-stick X-Axis"; - case guncon3_btn::bs_y: return "B-stick Y-Axis"; - case guncon3_btn::count: return "Count"; - } - - return unknown; - }); -} - -static const u8 KEY_TABLE[] = { - 0x91, 0xFD, 0x4C, 0x8B, 0x20, 0xC1, 0x7C, 0x09, 0x58, 0x14, 0xF6, 0x00, 0x52, 0x55, 0xBF, 0x41, - 0x75, 0xC0, 0x13, 0x30, 0xB5, 0xD0, 0x69, 0x85, 0x89, 0xBB, 0xD6, 0x88, 0xBC, 0x73, 0x18, 0x8D, - 0x58, 0xAB, 0x3D, 0x98, 0x5C, 0xF2, 0x48, 0xE9, 0xAC, 0x9F, 0x7A, 0x0C, 0x7C, 0x25, 0xD8, 0xFF, - 0xDC, 0x7D, 0x08, 0xDB, 0xBC, 0x18, 0x8C, 0x1D, 0xD6, 0x3C, 0x35, 0xE1, 0x2C, 0x14, 0x8E, 0x64, - 0x83, 0x39, 0xB0, 0xE4, 0x4E, 0xF7, 0x51, 0x7B, 0xA8, 0x13, 0xAC, 0xE9, 0x43, 0xC0, 0x08, 0x25, - 0x0E, 0x15, 0xC4, 0x20, 0x93, 0x13, 0xF5, 0xC3, 0x48, 0xCC, 0x47, 0x1C, 0xC5, 0x20, 0xDE, 0x60, - 0x55, 0xEE, 0xA0, 0x40, 0xB4, 0xE7, 0x74, 0x95, 0xB0, 0x46, 0xEC, 0xF0, 0xA5, 0xB8, 0x23, 0xC8, - 0x04, 0x06, 0xFC, 0x28, 0xCB, 0xF8, 0x17, 0x2C, 0x25, 0x1C, 0xCB, 0x18, 0xE3, 0x6C, 0x80, 0x85, - 0xDD, 0x7E, 0x09, 0xD9, 0xBC, 0x19, 0x8F, 0x1D, 0xD4, 0x3D, 0x37, 0xE1, 0x2F, 0x15, 0x8D, 0x64, - 0x06, 0x04, 0xFD, 0x29, 0xCF, 0xFA, 0x14, 0x2E, 0x25, 0x1F, 0xC9, 0x18, 0xE3, 0x6D, 0x81, 0x84, - 0x80, 0x3B, 0xB1, 0xE5, 0x4D, 0xF7, 0x51, 0x78, 0xA9, 0x13, 0xAD, 0xE9, 0x80, 0xC1, 0x0B, 0x25, - 0x93, 0xFC, 0x4D, 0x89, 0x23, 0xC2, 0x7C, 0x0B, 0x59, 0x15, 0xF6, 0x01, 0x50, 0x55, 0xBF, 0x81, - 0x75, 0xC3, 0x10, 0x31, 0xB5, 0xD3, 0x69, 0x84, 0x89, 0xBA, 0xD6, 0x89, 0xBD, 0x70, 0x19, 0x8E, - 0x58, 0xA8, 0x3D, 0x9B, 0x5D, 0xF0, 0x49, 0xE8, 0xAD, 0x9D, 0x7A, 0x0D, 0x7E, 0x24, 0xDA, 0xFC, - 0x0D, 0x14, 0xC5, 0x23, 0x91, 0x11, 0xF5, 0xC0, 0x4B, 0xCD, 0x44, 0x1C, 0xC5, 0x21, 0xDF, 0x61, - 0x54, 0xED, 0xA2, 0x81, 0xB7, 0xE5, 0x74, 0x94, 0xB0, 0x47, 0xEE, 0xF1, 0xA5, 0xBB, 0x21, 0xC8}; - -#pragma pack(push, 1) -struct GunCon3_data -{ - uint8_t : 1; - uint8_t btn_a2 : 1; - uint8_t btn_a1 : 1; - uint8_t btn_c2 : 1; - uint8_t : 4; - - uint8_t : 1; - uint8_t btn_b2 : 1; - uint8_t btn_b1 : 1; - uint8_t : 2; - uint8_t btn_trigger : 1; - uint8_t : 1; - uint8_t btn_c1 : 1; - - uint8_t : 6; - uint8_t btn_b3 : 1; - uint8_t btn_a3 : 1; - - int16_t gun_x; - int16_t gun_y; - int16_t gun_z; - uint8_t stick_bx; - uint8_t stick_by; - uint8_t stick_ax; - uint8_t stick_ay; - - uint8_t checksum; - uint8_t keyindex; -}; -#pragma pack(pop) - -static void guncon3_encode(const GunCon3_data* gc, u8* data, const u8* key) -{ - std::memcpy(data, gc, sizeof(GunCon3_data)); - - u8 key_offset = ((((key[1] ^ key[2]) - key[3] - key[4]) ^ key[5]) + key[6] - key[7]) ^ data[14]; - u8 key_index = 0; - - for (int i = 0; i < 13; i++) - { - u8 byte = data[i]; - for (int j = 0; j < 3; j++) - { - u8 bkey = KEY_TABLE[key_offset]; - u8 keyr = key[++key_index]; - if (key_index == 7) - key_index = 0; - - if ((bkey & 3) == 0) - byte = (byte + bkey) + keyr; - else if ((bkey & 3) == 1) - byte = (byte - bkey) - keyr; - else - byte = (byte ^ bkey) ^ keyr; - - key_offset++; - } - data[i] = byte; - } - - data[13] = ((((((key[7] + data[0] - data[1] - data[2]) ^ data[3]) + data[4] + data[5]) ^ data[6]) ^ data[7]) + data[8] + data[9] - data[10] - data[11]) ^ data[12]; -} - -usb_device_guncon3::usb_device_guncon3(u32 controller_index, const std::array& location) - : usb_device_emulated(location), m_controller_index(controller_index) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0110, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x08, - .idVendor = 0x0b9a, - .idProduct = 0x0800, - .bcdDevice = 0x8000, - .iManufacturer = 0x00, - .iProduct = 0x00, - .iSerialNumber = 0x00, - .bNumConfigurations = 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 0x0020, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0x00, - .bMaxPower = 0x32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x02, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, - .iInterface = 0x00})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x02, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0008, - .bInterval = 0x10})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x82, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x000f, - .bInterval = 0x04})); -} - -usb_device_guncon3::~usb_device_guncon3() -{ -} - -void usb_device_guncon3::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 100; - - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); -} - -extern bool is_input_allowed(); - -void usb_device_guncon3::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; - transfer->expected_time = get_timestamp() + 4000; - - if ((endpoint & 0x80) == LIBUSB_ENDPOINT_OUT) - { - std::memcpy(m_key.data(), buf, std::min(buf_size, m_key.size())); - return; - } - // else ENDPOINT_IN - - ensure(buf_size >= sizeof(GunCon3_data)); - - GunCon3_data gc{}; - gc.stick_ax = gc.stick_ay = gc.stick_bx = gc.stick_by = 0x7f; - - if (!is_input_allowed()) - { - guncon3_encode(&gc, buf, m_key.data()); - return; - } - - if (g_cfg.io.mouse == mouse_handler::null) - { - guncon3_log.warning("GunCon3 requires a Mouse Handler enabled"); - guncon3_encode(&gc, buf, m_key.data()); - return; - } - - if (m_controller_index >= g_cfg_guncon3.players.size()) - { - guncon3_log.warning("GunCon3 controllers are only supported for Player1 to Player%d", g_cfg_guncon3.players.size()); - guncon3_encode(&gc, buf, m_key.data()); - return; - } - - const auto input_callback = [&gc](guncon3_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; - - switch (btn) - { - case guncon3_btn::trigger: gc.btn_trigger |= 1; break; - case guncon3_btn::a1: gc.btn_a1 |= 1; break; - case guncon3_btn::a2: gc.btn_a2 |= 1; break; - case guncon3_btn::a3: gc.btn_a3 |= 1; break; - case guncon3_btn::b1: gc.btn_b1 |= 1; break; - case guncon3_btn::b2: gc.btn_b2 |= 1; break; - case guncon3_btn::b3: gc.btn_b3 |= 1; break; - case guncon3_btn::c1: gc.btn_c1 |= 1; break; - case guncon3_btn::c2: gc.btn_c2 |= 1; break; - case guncon3_btn::as_x: gc.stick_ax = static_cast(value); break; - case guncon3_btn::as_y: gc.stick_ay = static_cast(value); break; - case guncon3_btn::bs_x: gc.stick_bx = static_cast(value); break; - case guncon3_btn::bs_y: gc.stick_by = static_cast(value); break; - case guncon3_btn::count: break; - } - }; - - const auto& cfg = ::at32(g_cfg_guncon3.players, m_controller_index); - - { - std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_pad_thread(); - const auto& pads = gamepad_handler->GetPads(); - const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) - { - cfg->handle_input(pad, true, input_callback); - } - } - - { - auto& mouse_handler = g_fxo->get(); - std::lock_guard mouse_lock(mouse_handler.mutex); - - mouse_handler.Init(4); - - const u32 mouse_index = g_cfg.io.mouse == mouse_handler::basic ? 0 : m_controller_index; - if (mouse_index >= mouse_handler.GetMice().size()) - { - guncon3_encode(&gc, buf, m_key.data()); - return; - } - - const Mouse& mouse_data = ::at32(mouse_handler.GetMice(), mouse_index); - cfg->handle_input(mouse_data, input_callback); - - if (mouse_data.x_max <= 0 || mouse_data.y_max <= 0) - { - guncon3_encode(&gc, buf, m_key.data()); - return; - } - - // Expand 0..+wh to -32767..+32767 - gc.gun_x = (mouse_data.x_pos * USHRT_MAX / mouse_data.x_max) - SHRT_MAX; - gc.gun_y = (mouse_data.y_pos * -USHRT_MAX / mouse_data.y_max) + SHRT_MAX; - } - - guncon3_encode(&gc, buf, m_key.data()); -} diff --git a/rpcs3/Emu/Io/GunCon3.h b/rpcs3/Emu/Io/GunCon3.h deleted file mode 100644 index df013e4240..0000000000 --- a/rpcs3/Emu/Io/GunCon3.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_guncon3 : public usb_device_emulated -{ -public: - usb_device_guncon3(u32 controller_index, const std::array& location); - ~usb_device_guncon3(); - - 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; - -private: - u32 m_controller_index; - std::array m_key{}; -}; diff --git a/rpcs3/Emu/Io/Infinity.cpp b/rpcs3/Emu/Io/Infinity.cpp deleted file mode 100644 index ff4ce9e85b..0000000000 --- a/rpcs3/Emu/Io/Infinity.cpp +++ /dev/null @@ -1,487 +0,0 @@ -#include "stdafx.h" -#include "Infinity.h" - -#include - -#include "Crypto/aes.h" -#include "Crypto/sha1.h" - -LOG_CHANNEL(infinity_log, "infinity"); - -infinity_base g_infinitybase; - -static constexpr std::array SHA1_CONSTANT = { - 0xAF, 0x62, 0xD2, 0xEC, 0x04, 0x91, 0x96, 0x8C, 0xC5, 0x2A, 0x1A, 0x71, 0x65, 0xF8, 0x65, 0xFE, - 0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6e, 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33}; - -void infinity_figure::save() -{ - if (!inf_file) - { - infinity_log.error("Tried to save infinity figure to file but no infinity figure is active!"); - return; - } - inf_file.seek(0, fs::seek_set); - inf_file.write(data.data(), 0x14 * 0x10); -} - -u8 infinity_base::generate_checksum(const std::array& data, int num_of_bytes) const -{ - int checksum = 0; - for (int i = 0; i < num_of_bytes; i++) - { - checksum += data[i]; - } - return (checksum & 0xFF); -} - -void infinity_base::get_blank_response(u8 sequence, std::array& reply_buf) -{ - reply_buf[0] = 0xaa; - reply_buf[1] = 0x01; - reply_buf[2] = sequence; - reply_buf[3] = generate_checksum(reply_buf, 3); -} - -void infinity_base::descramble_and_seed(u8* buf, u8 sequence, std::array& reply_buf) -{ - u64 value = u64(buf[4]) << 56 | u64(buf[5]) << 48 | u64(buf[6]) << 40 | u64(buf[7]) << 32 | - u64(buf[8]) << 24 | u64(buf[9]) << 16 | u64(buf[10]) << 8 | u64(buf[11]); - u32 seed = descramble(value); - generate_seed(seed); - get_blank_response(sequence, reply_buf); -} - -void infinity_base::get_next_and_scramble(u8 sequence, std::array& reply_buf) -{ - const u32 next_random = get_next(); - const u64 scrambled_next_random = scramble(next_random, 0); - reply_buf = {0xAA, 0x09, sequence}; - reply_buf[3] = u8((scrambled_next_random >> 56) & 0xFF); - reply_buf[4] = u8((scrambled_next_random >> 48) & 0xFF); - reply_buf[5] = u8((scrambled_next_random >> 40) & 0xFF); - reply_buf[6] = u8((scrambled_next_random >> 32) & 0xFF); - reply_buf[7] = u8((scrambled_next_random >> 24) & 0xFF); - reply_buf[8] = u8((scrambled_next_random >> 16) & 0xFF); - reply_buf[9] = u8((scrambled_next_random >> 8) & 0xFF); - reply_buf[10] = u8(scrambled_next_random & 0xFF); - reply_buf[11] = generate_checksum(reply_buf, 11); -} - -u32 infinity_base::descramble(u64 num_to_descramble) -{ - u64 mask = 0x8E55AA1B3999E8AA; - u32 ret = 0; - - for (int i = 0; i < 64; i++) - { - if (mask & 0x8000000000000000) - { - ret = (ret << 1) | (num_to_descramble & 0x01); - } - - num_to_descramble >>= 1; - mask <<= 1; - } - - return ret; -} - -u64 infinity_base::scramble(u32 num_to_scramble, u32 garbage) -{ - u64 mask = 0x8E55AA1B3999E8AA; - u64 ret = 0; - - for (int i = 0; i < 64; i++) - { - ret <<= 1; - - if ((mask & 1) != 0) - { - ret |= (num_to_scramble & 1); - num_to_scramble >>= 1; - } - else - { - ret |= (garbage & 1); - garbage >>= 1; - } - - mask >>= 1; - } - - return ret; -} - -void infinity_base::generate_seed(u32 seed) -{ - random_a = 0xF1EA5EED; - random_b = seed; - random_c = seed; - random_d = seed; - - for (int i = 0; i < 23; i++) - { - get_next(); - } -} - -u32 infinity_base::get_next() -{ - u32 a = random_a; - u32 b = random_b; - u32 c = random_c; - u32 ret = std::rotl(random_b, 27); - - const u32 temp = (a + ((ret ^ 0xFFFFFFFF) + 1)); - b ^= std::rotl(c, 17); - a = random_d; - c += a; - ret = b + temp; - a += temp; - - random_c = a; - random_a = b; - random_b = c; - random_d = ret; - - return ret; -} - -void infinity_base::get_present_figures(u8 sequence, std::array& reply_buf) -{ - int x = 3; - for (u8 i = 0; i < figures.size(); i++) - { - u8 slot = i == 0 ? 0x10 : (i < 4) ? 0x20 : - 0x30; - if (figures[i].present) - { - reply_buf[x] = slot + figures[i].order_added; - reply_buf[x + 1] = 0x09; - x += 2; - } - } - reply_buf[0] = 0xaa; - reply_buf[1] = x - 2; - reply_buf[2] = sequence; - reply_buf[x] = generate_checksum(reply_buf, x); -} - -infinity_figure& infinity_base::get_figure_by_order(u8 order_added) -{ - for (u8 i = 0; i < figures.size(); i++) - { - if (figures[i].order_added == order_added) - { - return figures[i]; - } - } - return figures[0]; -} - -u8 infinity_base::derive_figure_position(u8 position) -{ - switch (position) - { - case 0: - case 1: - case 2: - return 1; - case 3: - case 4: - case 5: - return 2; - case 6: - case 7: - case 8: - return 3; - - default: - return 0; - } -} - -void infinity_base::query_block(u8 fig_num, u8 block, std::array& reply_buf, u8 sequence) -{ - std::lock_guard lock(infinity_mutex); - - infinity_figure& figure = get_figure_by_order(fig_num); - - reply_buf[0] = 0xaa; - reply_buf[1] = 0x12; - reply_buf[2] = sequence; - reply_buf[3] = 0x00; - const u8 file_block = (block == 0) ? 1 : (block * 4); - if (figure.present && file_block < 20) - { - memcpy(&reply_buf[4], figure.data.data() + (16 * file_block), 16); - } - reply_buf[20] = generate_checksum(reply_buf, 20); -} - -void infinity_base::write_block(u8 fig_num, u8 block, const u8* to_write_buf, - std::array& reply_buf, u8 sequence) -{ - std::lock_guard lock(infinity_mutex); - - infinity_figure& figure = get_figure_by_order(fig_num); - - reply_buf[0] = 0xaa; - reply_buf[1] = 0x02; - reply_buf[2] = sequence; - reply_buf[3] = 0x00; - const u8 file_block = (block == 0) ? 1 : (block * 4); - if (figure.present && file_block < 20) - { - memcpy(figure.data.data() + (file_block * 16), to_write_buf, 16); - figure.save(); - } - reply_buf[4] = generate_checksum(reply_buf, 4); -} - -void infinity_base::get_figure_identifier(u8 fig_num, u8 sequence, std::array& reply_buf) -{ - std::lock_guard lock(infinity_mutex); - - infinity_figure& figure = get_figure_by_order(fig_num); - - reply_buf[0] = 0xaa; - reply_buf[1] = 0x09; - reply_buf[2] = sequence; - reply_buf[3] = 0x00; - - if (figure.present) - { - memcpy(&reply_buf[4], figure.data.data(), 7); - } - reply_buf[11] = generate_checksum(reply_buf, 11); -} - -bool infinity_base::has_figure_been_added_removed() const -{ - return !m_figure_added_removed_responses.empty(); -} - -std::array infinity_base::pop_added_removed_response() -{ - std::array response = m_figure_added_removed_responses.front(); - m_figure_added_removed_responses.pop(); - return response; -} - -bool infinity_base::remove_figure(u8 position) -{ - std::lock_guard lock(infinity_mutex); - infinity_figure& figure = figures[position]; - - if (!figure.present) - { - return false; - } - - position = derive_figure_position(position); - if (position == 0) - { - return false; - } - - figure.present = false; - - std::array figure_change_response = {0xab, 0x04, position, 0x09, figure.order_added, 0x01}; - figure_change_response[6] = generate_checksum(figure_change_response, 6); - m_figure_added_removed_responses.push(figure_change_response); - - figure.save(); - figure.inf_file.close(); - return true; -} - -u32 infinity_base::load_figure(const std::array& buf, fs::file in_file, u8 position) -{ - std::lock_guard lock(infinity_mutex); - u8 order_added; - - std::vector sha1_calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1}; - for (int i = 0; i < 7; i++) - { - sha1_calc.push_back(buf[i]); - } - - sha1_context ctx; - u8 output[20]; - - sha1_starts(&ctx); - sha1_update(&ctx, sha1_calc.data(), sha1_calc.size()); - sha1_finish(&ctx, output); - - std::array key{}; - for (int i = 0; i < 4; i++) - { - for (int x = 0; x < 4; x++) - { - key[x + (i * 4)] = output[(3 - x) + (i * 4)]; - } - } - - aes_context aes; - aes_setkey_dec(&aes, key.data(), 128); - std::array infinity_decrypted_block{}; - aes_crypt_ecb(&aes, AES_DECRYPT, &buf[16], infinity_decrypted_block.data()); - - u32 number = u32(infinity_decrypted_block[1]) << 16 | u32(infinity_decrypted_block[2]) << 8 | - u32(infinity_decrypted_block[3]); - - infinity_figure& figure = figures[position]; - - figure.inf_file = std::move(in_file); - memcpy(figure.data.data(), buf.data(), figure.data.size()); - figure.present = true; - if (figure.order_added == 255) - { - figure.order_added = m_figure_order; - m_figure_order++; - } - order_added = figure.order_added; - - position = derive_figure_position(position); - if (position == 0) - { - return 0; - } - - std::array figure_change_response = {0xab, 0x04, position, 0x09, order_added, 0x00}; - figure_change_response[6] = generate_checksum(figure_change_response, 6); - m_figure_added_removed_responses.push(figure_change_response); - - return number; -} - -usb_device_infinity::usb_device_infinity(const std::array& location) - : usb_device_emulated(location) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x200, 0x0, 0x0, 0x0, 0x20, 0x0E6F, 0x0129, 0x200, 0x1, 0x2, 0x3, 0x1}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x29, 0x1, 0x1, 0x0, 0x80, 0xFA})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 0x001d})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x3, 0x20, 0x1})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x1, 0x3, 0x20, 0x1})); -} - -usb_device_infinity::~usb_device_infinity() -{ -} - -std::shared_ptr usb_device_infinity::make_instance(u32, const std::array& location) -{ - return std::make_shared(location); -} - -u16 usb_device_infinity::get_num_emu_devices() -{ - return 1; -} - -void usb_device_infinity::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); -} - -void usb_device_infinity::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) -{ - ensure(buf_size == 0x20); - - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - - if (endpoint == 0x81) - { - // Respond after FF command - transfer->expected_time = get_timestamp() + 1000; - if (g_infinitybase.has_figure_been_added_removed()) - { - memcpy(buf, g_infinitybase.pop_added_removed_response().data(), 0x20); - } - else if (!m_queries.empty()) - { - memcpy(buf, m_queries.front().data(), 0x20); - m_queries.pop(); - } - } - else if (endpoint == 0x01) - { - const u8 command = buf[2]; - const u8 sequence = buf[3]; - - transfer->expected_time = get_timestamp() + 500; - std::array q_result{}; - - switch (command) - { - case 0x80: - { - q_result = {0xaa, 0x15, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x03, 0x02, 0x09, 0x09, 0x43, - 0x20, 0x32, 0x62, 0x36, 0x36, 0x4b, 0x34, 0x99, 0x67, 0x31, 0x93, 0x8c}; - break; - } - case 0x81: - { - // Initiate Challenge - g_infinitybase.descramble_and_seed(buf, sequence, q_result); - break; - } - case 0x83: - { - // Challenge Response - g_infinitybase.get_next_and_scramble(sequence, q_result); - break; - } - case 0x90: - case 0x92: - case 0x93: - case 0x95: - case 0x96: - { - // Color commands - g_infinitybase.get_blank_response(sequence, q_result); - break; - } - case 0xA1: - { - // Get Present Figures - g_infinitybase.get_present_figures(sequence, q_result); - break; - } - case 0xA2: - { - // Read Block from Figure - g_infinitybase.query_block(buf[4], buf[5], q_result, sequence); - break; - } - case 0xA3: - { - // Write block to figure - g_infinitybase.write_block(buf[4], buf[5], &buf[7], q_result, sequence); - break; - } - case 0xB4: - { - // Get figure ID - g_infinitybase.get_figure_identifier(buf[4], sequence, q_result); - break; - } - case 0xB5: - { - // Get status? - g_infinitybase.get_blank_response(sequence, q_result); - break; - } - default: - infinity_log.error("Unhandled Query Type: 0x%02X", command); - break; - } - - m_queries.push(q_result); - } -} diff --git a/rpcs3/Emu/Io/Infinity.h b/rpcs3/Emu/Io/Infinity.h deleted file mode 100644 index 45ea522286..0000000000 --- a/rpcs3/Emu/Io/Infinity.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" -#include "util/mutex.h" -#include -#include - -struct infinity_figure -{ - fs::file inf_file; - std::array data{}; - bool present = false; - u8 order_added = 255; - void save(); -}; - -class infinity_base -{ -public: - void get_blank_response(u8 sequence, std::array& reply_buf); - void descramble_and_seed(u8* buf, u8 sequence, std::array& reply_buf); - void get_next_and_scramble(u8 sequence, std::array& reply_buf); - void get_present_figures(u8 sequence, std::array& reply_buf); - void query_block(u8 fig_num, u8 block, std::array& reply_buf, u8 sequence); - void write_block(u8 fig_num, u8 block, const u8* to_write_buf, std::array& reply_buf, u8 sequence); - void get_figure_identifier(u8 fig_num, u8 sequence, std::array& reply_buf); - bool has_figure_been_added_removed() const; - std::array pop_added_removed_response(); - - bool remove_figure(u8 position); - u32 load_figure(const std::array& buf, fs::file in_file, u8 position); - -protected: - shared_mutex infinity_mutex; - std::array figures; - -private: - u8 generate_checksum(const std::array& data, int num_of_bytes) const; - u32 descramble(u64 num_to_descramble); - u64 scramble(u32 num_to_scramble, u32 garbage); - void generate_seed(u32 seed); - u32 get_next(); - infinity_figure& get_figure_by_order(u8 order_added); - u8 derive_figure_position(u8 position); - - u32 random_a = 0; - u32 random_b = 0; - u32 random_c = 0; - u32 random_d = 0; - - u8 m_figure_order = 0; - std::queue> m_figure_added_removed_responses; -}; - -extern infinity_base g_infinitybase; - -class usb_device_infinity : public usb_device_emulated -{ -public: - usb_device_infinity(const std::array& location); - ~usb_device_infinity(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - -protected: - std::queue> m_queries; -}; diff --git a/rpcs3/Emu/Io/RB3MidiDrums.cpp b/rpcs3/Emu/Io/RB3MidiDrums.cpp deleted file mode 100644 index 999182ae09..0000000000 --- a/rpcs3/Emu/Io/RB3MidiDrums.cpp +++ /dev/null @@ -1,840 +0,0 @@ -// Rock Band 3 MIDI Pro Adapter Emulator (drums Mode) - -#include "stdafx.h" -#include "RB3MidiDrums.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/Io/rb3drums_config.h" - -using namespace std::chrono_literals; - -LOG_CHANNEL(rb3_midi_drums_log); - -namespace controller -{ - - // Bit flags by byte index. - - constexpr usz FLAG = 0; - constexpr usz INDEX = 1; - - using FlagByIndex = std::array; - - constexpr FlagByIndex BUTTON_1 = {0x01, 0}; - constexpr FlagByIndex BUTTON_2 = {0x02, 0}; - constexpr FlagByIndex BUTTON_3 = {0x04, 0}; - constexpr FlagByIndex BUTTON_4 = {0x08, 0}; - constexpr FlagByIndex BUTTON_5 = {0x10, 0}; - constexpr FlagByIndex BUTTON_6 = {0x20, 0}; - // constexpr FlagByIndex BUTTON_7 = {0x40, 0}; - // constexpr FlagByIndex BUTTON_8 = {0x80, 0}; - - constexpr FlagByIndex BUTTON_9 = {0x01, 1}; - constexpr FlagByIndex BUTTON_10 = {0x02, 1}; - constexpr FlagByIndex BUTTON_11 = {0x04, 1}; - constexpr FlagByIndex BUTTON_12 = {0x08, 1}; - // constexpr FlagByIndex BUTTON_13 = {0x10, 1}; - - constexpr usz DPAD_INDEX = 2; - enum class DPad : u8 - { - Up = 0x00, - Right = 0x02, - Down = 0x04, - Left = 0x06, - Center = 0x08, - }; - - constexpr u8 AXIS_CENTER = 0x7F; - - constexpr std::array default_state = { - 0x00, // buttons 1 to 8 - 0x00, // buttons 9 to 13 - static_cast(controller::DPad::Center), - controller::AXIS_CENTER, // x axis - controller::AXIS_CENTER, // y axis - controller::AXIS_CENTER, // z axis - controller::AXIS_CENTER, // w axis - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, // yellow drum/cymbal velocity - 0x00, // red drum/cymbal velocity - 0x00, // green drum/cymbal velocity - 0x00, // blue drum/cymbal velocity - 0x00, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0x02, - 0x00, - 0x02, - 0x00, - 0x02, - 0x00}; - -} // namespace controller - -namespace drum -{ - - // Hold each hit for a period of time. Rock band doesn't pick up a single tick. - std::chrono::milliseconds hit_duration() - { - return std::chrono::milliseconds(g_cfg_rb3drums.pulse_ms); - } - - // Scale velocity from midi to what rock band expects. - u8 scale_velocity(u8 value) - { - return (0xFF - (2 * value)); - } - - constexpr usz FLAG = controller::FLAG; - constexpr usz INDEX = controller::INDEX; - - using FlagByIndex = controller::FlagByIndex; - - constexpr FlagByIndex GREEN = controller::BUTTON_2; - constexpr FlagByIndex RED = controller::BUTTON_3; - constexpr FlagByIndex YELLOW = controller::BUTTON_4; - constexpr FlagByIndex BLUE = controller::BUTTON_1; - constexpr FlagByIndex KICK_PEDAL = controller::BUTTON_5; - constexpr FlagByIndex HIHAT_PEDAL = controller::BUTTON_6; - - constexpr FlagByIndex IS_DRUM = controller::BUTTON_11; - constexpr FlagByIndex IS_CYMBAL = controller::BUTTON_12; - - // constexpr FlagByIndex BACK_BUTTON = controller::BUTTON_3; - constexpr FlagByIndex START_BUTTON = controller::BUTTON_10; - // constexpr FlagByIndex SYSTEM_BUTTON = controller::BUTTON_13; - constexpr FlagByIndex SELECT_BUTTON = controller::BUTTON_9; - - rb3drums::KitState start_state() - { - rb3drums::KitState s{}; - s.expiry = std::chrono::steady_clock::now() + drum::hit_duration(); - s.start = true; - return s; - } - - rb3drums::KitState select_state() - { - rb3drums::KitState s{}; - s.expiry = std::chrono::steady_clock::now() + drum::hit_duration(); - s.select = true; - return s; - } - - rb3drums::KitState toggle_hold_kick_state() - { - rb3drums::KitState s{}; - s.expiry = std::chrono::steady_clock::now() + drum::hit_duration(); - s.toggle_hold_kick = true; - return s; - } - - rb3drums::KitState kick_state() - { - rb3drums::KitState s{}; - s.expiry = std::chrono::steady_clock::now() + drum::hit_duration(); - s.kick_pedal = 127; - return s; - } - -} // namespace drum - -namespace midi -{ - - u8 min_velocity() - { - return g_cfg_rb3drums.minimum_velocity; - } - - Note str_to_note(const std::string_view name) - { - static const std::unordered_map mapping{ - {"Invalid", Note::Invalid}, - {"Kick", Note::Kick}, - {"HihatPedal", Note::HihatPedal}, - {"Snare", Note::Snare}, - {"SnareRim", Note::SnareRim}, - {"HiTom", Note::HiTom}, - {"LowTom", Note::LowTom}, - {"FloorTom", Note::FloorTom}, - {"HihatWithPedalUp", Note::HihatWithPedalUp}, - {"Hihat", Note::Hihat}, - {"Ride", Note::Ride}, - {"Crash", Note::Crash}, - }; - auto it = mapping.find(name); - return it != std::end(mapping) ? it->second : Note::Invalid; - } - - std::optional> parse_midi_override(const std::string_view config) - { - auto split = fmt::split(config, {"="}); - if (split.size() != 2) - { - return {}; - } - uint64_t id_int = 0; - if (!try_to_uint64(&id_int, split[0], 0, 255)) - { - rb3_midi_drums_log.warning("midi override: %s is not a valid midi id", split[0]); - return {}; - } - auto id = static_cast(id_int); - auto note = str_to_note(split[1]); - if (note == Note::Invalid) - { - rb3_midi_drums_log.warning("midi override: %s is not a valid note", split[1]); - return {}; - } - rb3_midi_drums_log.success("found valid midi override: %s", config); - return {{id, note}}; - } - - std::unordered_map create_id_to_note_mapping() - { - std::unordered_map mapping{ - {Id::MidiCC, Note::Kick}, - {Id::Kick0, Note::Kick}, - {Id::Kick1, Note::Kick}, - {Id::Kick2, Note::Kick}, - {Id::HihatPedal, Note::HihatPedal}, - {Id::HihatPedalPartial, Note::HihatPedal}, - {Id::Snare0, Note::Snare}, - {Id::Snare1, Note::Snare}, - {Id::Snare2, Note::Snare}, - {Id::Snare3, Note::Snare}, - {Id::Snare4, Note::Snare}, - {Id::SnareRim, Note::SnareRim}, - {Id::HiTom0, Note::HiTom}, - {Id::HiTom1, Note::HiTom}, - {Id::LowTom0, Note::LowTom}, - {Id::LowTom1, Note::LowTom}, - {Id::FloorTom0, Note::FloorTom}, - {Id::FloorTom1, Note::FloorTom}, - {Id::Hihat0, Note::Hihat}, - {Id::Hihat1, Note::Hihat}, - {Id::Hihat2, Note::Hihat}, - {Id::Hihat3, Note::Hihat}, - {Id::HihatWithPedalUp, Note::Hihat}, - {Id::Ride0, Note::Ride}, - {Id::Ride1, Note::Ride}, - {Id::Ride2, Note::Ride}, - {Id::Ride3, Note::Ride}, - {Id::Crash0, Note::Crash}, - {Id::Crash1, Note::Crash}, - {Id::Crash2, Note::Crash}, - {Id::Crash3, Note::Crash}, - }; - - // Apply configured overrides. - const std::vector segments = fmt::split(g_cfg_rb3drums.midi_overrides.to_string(), {","}); - for (const std::string& segment : segments) - { - if (const auto midi_override = parse_midi_override(segment)) - { - const auto id = midi_override->first; - const auto note = midi_override->second; - mapping[id] = note; - } - } - return mapping; - } - - namespace combo - { - - std::vector parse_combo(const std::string_view name, const std::string_view csv) - { - if (csv.empty()) - { - return {}; - } - std::vector notes; - const auto& note_names = fmt::split(csv, {","}); - for (const auto& note_name : note_names) - { - const auto note = str_to_note(note_name); - if (note != midi::Note::Invalid) - { - notes.push_back(static_cast(note)); - } - else - { - rb3_midi_drums_log.warning("invalid note '%s' in configured combo '%s'", note_name, name); - } - } - return notes; - } - - std::chrono::milliseconds window() - { - return std::chrono::milliseconds{g_cfg_rb3drums.combo_window_ms}; - } - - } // namespace combo - -} // namespace midi - -namespace -{ - - void set_flag(u8* buf, [[maybe_unused]] std::string_view name, const controller::FlagByIndex& fbi) - { - auto i = fbi[drum::INDEX]; - auto flag = fbi[drum::FLAG]; - buf[i] |= flag; - // rb3_midi_drums_log.success("wrote flag %x at index %d", flag, i); - } - - void set_flag_if_any(u8* buf, std::string_view name, const controller::FlagByIndex& fbi, const std::vector velocities) - { - if (std::none_of(velocities.begin(), velocities.end(), [](u8 velocity) - { - return velocity >= midi::min_velocity(); - })) - { - return; - } - set_flag(buf, name, fbi); - } - -} // namespace - -usb_device_rb3_midi_drums::Definition::Definition(std::string name, const std::string_view csv, const std::function create_state) - : name{std::move(name)}, notes{midi::combo::parse_combo(this->name, csv)}, create_state{create_state} -{ -} - -usb_device_rb3_midi_drums::usb_device_rb3_midi_drums(const std::array& location, const std::string& device_name) - : usb_device_emulated(location) -{ - m_id_to_note_mapping = midi::create_id_to_note_mapping(); - combo.reload_definitions(); - - UsbDeviceDescriptor descriptor{}; - descriptor.bcdDevice = 0x0200; - descriptor.bDeviceClass = 0x00; - descriptor.bDeviceSubClass = 0x00; - descriptor.bDeviceProtocol = 0x00; - descriptor.bMaxPacketSize0 = 64; - descriptor.idVendor = 0x12BA; // Harmonix - descriptor.idProduct = 0x0210; // Drums - descriptor.bcdDevice = 0x01; - descriptor.iManufacturer = 0x01; - descriptor.iProduct = 0x02; - descriptor.iSerialNumber = 0x00; - descriptor.bNumConfigurations = 0x01; - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, descriptor); - - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{41, 1, 1, 0, 0x80, 32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0, 0, 2, 3, 0, 0, 0})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 137})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0040, 10})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x0040, 10})); - - usb_device_emulated::add_string("Licensed by Sony Computer Entertainment America"); - usb_device_emulated::add_string("Harmonix RB3 MIDI Drums Interface for PlayStation®3"); - - // connect to midi device - midi_in = rtmidi_in_create_default(); - ensure(midi_in); - - if (!midi_in->ok) - { - rb3_midi_drums_log.error("Could not get MIDI in ptr: %s", midi_in->msg); - return; - } - - const RtMidiApi api = rtmidi_in_get_current_api(midi_in); - - if (!midi_in->ok) - { - rb3_midi_drums_log.error("Could not get MIDI api: %s", midi_in->msg); - return; - } - - if (const char* api_name = rtmidi_api_name(api)) - { - rb3_midi_drums_log.notice("Using %s api", api_name); - } - else - { - rb3_midi_drums_log.warning("Could not get MIDI api name"); - } - - rtmidi_in_ignore_types(midi_in, false, true, true); - - const u32 port_count = rtmidi_get_port_count(midi_in); - - if (!midi_in->ok || port_count == umax) - { - rb3_midi_drums_log.error("Could not get MIDI port count: %s", midi_in->msg); - return; - } - - for (u32 port_number = 0; port_number < port_count; port_number++) - { - char buf[128]{}; - s32 size = sizeof(buf); - if (rtmidi_get_port_name(midi_in, port_number, buf, &size) == -1 || !midi_in->ok) - { - rb3_midi_drums_log.error("Error getting port name for port %d: %s", port_number, midi_in->msg); - return; - } - - rb3_midi_drums_log.notice("Found device with name: %s", buf); - - if (device_name == buf) - { - rtmidi_open_port(midi_in, port_number, "RPCS3 MIDI Drums Input"); - - if (!midi_in->ok) - { - rb3_midi_drums_log.error("Could not open port %d for device '%s': %s", port_number, device_name, midi_in->msg); - return; - } - - rb3_midi_drums_log.success("Connected to device: %s", device_name); - return; - } - } - - rb3_midi_drums_log.error("Could not find device with name: %s", device_name); -} - -usb_device_rb3_midi_drums::~usb_device_rb3_midi_drums() -{ - rtmidi_in_free(midi_in); -} - -static const std::array disabled_response = { - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x26, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00}; - -static const std::array enabled_response = { - 0xe9, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x26, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00}; - -void usb_device_rb3_midi_drums::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - - // configuration packets sent by rock band 3 - // we only really need to check 1 byte here to figure out if the game - // wants to enable midi data or disable it - if (bmRequestType == 0x21 && bRequest == 0x9 && wLength == 40) - { - if (buf_size < 3) - { - rb3_midi_drums_log.warning("buffer size < 3, bailing out early (buf_size=0x%x)", buf_size); - return; - } - - switch (buf[2]) - { - case 0x89: - rb3_midi_drums_log.notice("MIDI data enabled."); - buttons_enabled = true; - response_pos = 0; - break; - case 0x81: - rb3_midi_drums_log.notice("MIDI data disabled."); - buttons_enabled = false; - response_pos = 0; - break; - default: - rb3_midi_drums_log.warning("Unhandled SET_REPORT request: 0x%02X"); - break; - } - } - - // the game expects some sort of response to the configuration packet - else if (bmRequestType == 0xa1 && bRequest == 0x1) - { - // rb3_midi_drums_log.success("[control_transfer] config 0xa1 0x1 length %d", wLength); - - transfer->expected_count = buf_size; - if (buttons_enabled) - { - const usz remaining_bytes = enabled_response.size() - response_pos; - const usz copied_bytes = std::min(remaining_bytes, buf_size); - memcpy(buf, &enabled_response[response_pos], copied_bytes); - response_pos += copied_bytes; - } - else - { - const usz remaining_bytes = disabled_response.size() - response_pos; - const usz copied_bytes = std::min(remaining_bytes, buf_size); - memcpy(buf, &disabled_response[response_pos], copied_bytes); - response_pos += copied_bytes; - } - } - // else if (bmRequestType == 0x00 && bRequest == 0x9) - //{ - // // idk what this is but if I handle it we don't get input. - // rb3_midi_drums_log.success("handled -- request %x, type %x, length %x", bmRequestType, bRequest, wLength); - // } - // else if (bmRequestType == 0x80 && bRequest == 0x6) - //{ - // // idk what this is but if I handle it we don't get input. - // rb3_midi_drums_log.success("handled -- request %x, type %x, length %x", bmRequestType, bRequest, wLength); - // } - else if (bmRequestType == 0x21 && bRequest == 0x9 && wLength == 8) - { - // the game uses this request to do things like set the LEDs - // we don't have any LEDs, so do nothing - } - else - { - rb3_midi_drums_log.error("unhandled control_transfer: request %x, type %x, length %x", bmRequestType, bRequest, wLength); - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - } -} - -void usb_device_rb3_midi_drums::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; - // the real device takes 8ms to send a response, but there is - // no reason we can't make it faster - transfer->expected_time = get_timestamp() + 1'000; - - const auto& bytes = controller::default_state; - if (buf_size < bytes.size()) - { - rb3_midi_drums_log.warning("buffer size < %x, bailing out early (buf_size=0x%x)", bytes.size(), buf_size); - return; - } - memcpy(buf, bytes.data(), bytes.size()); - - if (g_cfg_rb3drums.reload_requested) - { - m_id_to_note_mapping = midi::create_id_to_note_mapping(); - combo.reload_definitions(); - } - - while (true) - { - u8 midi_msg[32]; - usz size = sizeof(midi_msg); - - // This returns a double as some sort of delta time, with -1.0 - // being used to signal an error. - if (rtmidi_in_get_message(midi_in, midi_msg, &size) == -1.0) - { - rb3_midi_drums_log.error("Error getting MIDI message: %s", midi_in->msg); - return; - } - - if (size == 0) - { - break; - } - - auto kit_state = parse_midi_message(midi_msg, size); - if (auto combo_state = combo.take_state()) - { - if (combo_state->toggle_hold_kick) - { - hold_kick = !hold_kick; - } - else - { - kit_states.push_back(std::move(combo_state.value())); - } - } - else - { - bool is_cancel = kit_state.snare >= midi::min_velocity(); - bool is_accept = kit_state.floor_tom >= midi::min_velocity(); - if (hold_kick && (is_cancel || is_accept)) - { - // Hold kick brings up the song category selector menu, which can be dismissed using accept/cancel buttons. - hold_kick = false; - } - else - { - kit_states.push_back(std::move(kit_state)); - } - } - } - - // Clean expired states. - auto now = std::chrono::steady_clock::now(); - kit_states.erase(std::remove_if(std::begin(kit_states), std::end(kit_states), [&now](const rb3drums::KitState& kit_state) - { - return now >= kit_state.expiry; - }), - std::end(kit_states)); - - bool cymbal_hit = false; - usz i = 0; - for (; i < kit_states.size(); ++i) - { - const auto& kit_state = kit_states[i]; - - // Rockband sometimes has trouble registering both hits when two cymbals are hit at once. - // To solve for this, we stagger cymbal hits so that they occur one after another instead of at the same time. - // Note that this is staggering by pulse_ms (30ms default) so a human is unlikely to notice it in practice. - if (g_cfg_rb3drums.stagger_cymbals && cymbal_hit && kit_state.is_cymbal()) - { - // Already have a cymbal applied, buffer other inputs. - break; - } - cymbal_hit = kit_state.is_cymbal(); - write_state(buf, kit_state); - } - - if (hold_kick) - { - write_state(buf, drum::kick_state()); - } - - // Extend expiry on buffered states since they are not active. - for (; i < kit_states.size(); ++i) - { - kit_states[i].expiry = now + drum::hit_duration(); - } -} - -rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_message(u8* msg, usz size) -{ - if (size < 3) - { - rb3_midi_drums_log.warning("parse_midi_message: encountered message with size less than 3 bytes"); - return rb3drums::KitState{}; - } - - auto status = msg[0]; - auto id = msg[1]; - auto value = msg[2]; - - if (status == 0x99) - { - return parse_midi_note(id, value); - } - if (status == g_cfg_rb3drums.midi_cc_status) - { - if (is_midi_cc(id, value)) - { - return parse_midi_note(static_cast(midi::Id::MidiCC), 127); - } - } - // Ignore non-"note on" midi status messages. - return rb3drums::KitState{}; -} - -midi::Note usb_device_rb3_midi_drums::id_to_note(midi::Id id) -{ - const auto it = m_id_to_note_mapping.find(id); - return it != m_id_to_note_mapping.cend() ? it->second : midi::Note::Invalid; -} - -rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_note(const u8 id, const u8 velocity) -{ - if (velocity < midi::min_velocity()) - { - // Must check here so we don't overwrite good values when applying states. - return rb3drums::KitState{}; - } - - rb3drums::KitState kit_state{}; - kit_state.expiry = std::chrono::steady_clock::now() + drum::hit_duration(); - const midi::Note note = id_to_note(static_cast(id)); - switch (note) - { - case midi::Note::Kick: kit_state.kick_pedal = velocity; break; - case midi::Note::HihatPedal: kit_state.hihat_pedal = velocity; break; - case midi::Note::Snare: kit_state.snare = velocity; break; - case midi::Note::SnareRim: kit_state.snare_rim = velocity; break; - case midi::Note::HiTom: kit_state.hi_tom = velocity; break; - case midi::Note::LowTom: kit_state.low_tom = velocity; break; - case midi::Note::FloorTom: kit_state.floor_tom = velocity; break; - case midi::Note::Hihat: kit_state.hihat = velocity; break; - case midi::Note::Ride: kit_state.ride = velocity; break; - case midi::Note::Crash: kit_state.crash = velocity; break; - default: - // Ignored note. - rb3_midi_drums_log.error("IGNORED NOTE: id = %x or %d", id, id); - return rb3drums::KitState{}; - } - - combo.add(static_cast(note)); - return kit_state; -} - -bool usb_device_rb3_midi_drums::is_midi_cc(const u8 id, const u8 value) -{ - if (id != g_cfg_rb3drums.midi_cc_number) - { - return false; - } - - const auto is_past_threshold = [](u8 value) - { - const u8 threshold = g_cfg_rb3drums.midi_cc_threshold; - return g_cfg_rb3drums.midi_cc_invert_threshold ? value < threshold : value > threshold; - }; - - if (midi_cc_triggered) - { - if (!is_past_threshold(value)) - { - // Reset triggered state when we fall back past threshold. - midi_cc_triggered = false; - } - } - else - { - if (is_past_threshold(value)) - { - midi_cc_triggered = true; - return true; - } - } - return false; -} - -void usb_device_rb3_midi_drums::write_state(u8* buf, const rb3drums::KitState& kit_state) -{ - // See: https://github.com/TheNathannator/PlasticBand/blob/main/Docs/Instruments/4-Lane%20Drums/PS3%20and%20Wii.md#input-info - - // Interestingly, because cymbals use the same visual track as drums, a hit on that color can only be a drum OR a cymbal. - // rockband handles this by taking a flag to indicate if the hit is a drum vs cymbal. - set_flag_if_any(buf, "red", drum::RED, {kit_state.snare}); - set_flag_if_any(buf, "yellow", drum::YELLOW, {kit_state.hi_tom, kit_state.hihat}); - set_flag_if_any(buf, "blue", drum::BLUE, {kit_state.low_tom, kit_state.ride}); // Rock band charts blue cymbal for both hihat open and ride sometimes. - set_flag_if_any(buf, "green", drum::GREEN, {kit_state.floor_tom, kit_state.crash}); - - // Additionally, Yellow (hihat) and Blue (ride) cymbals add dpad up or down, respectively. This allows rockband to disambiguate between tom+cymbals hit at the same time. - if (kit_state.hihat >= midi::min_velocity()) - { - buf[controller::DPAD_INDEX] = static_cast(controller::DPad::Up); - } - if (kit_state.ride >= midi::min_velocity()) - { - buf[controller::DPAD_INDEX] = static_cast(controller::DPad::Down); - } - - set_flag_if_any(buf, "is_drum", drum::IS_DRUM, {kit_state.snare, kit_state.hi_tom, kit_state.low_tom, kit_state.floor_tom}); - set_flag_if_any(buf, "is_cymbal", drum::IS_CYMBAL, {kit_state.hihat, kit_state.ride, kit_state.crash}); - - set_flag_if_any(buf, "kick_pedal", drum::KICK_PEDAL, {kit_state.kick_pedal}); - set_flag_if_any(buf, "hihat_pedal", drum::HIHAT_PEDAL, {kit_state.hihat_pedal}); - - buf[11] = drum::scale_velocity(std::max(kit_state.hi_tom, kit_state.hihat)); - buf[12] = drum::scale_velocity(kit_state.snare); - buf[13] = drum::scale_velocity(std::max(kit_state.floor_tom, kit_state.crash)); - buf[14] = drum::scale_velocity(std::max({kit_state.low_tom, kit_state.ride})); - - if (kit_state.start) - { - set_flag(buf, "start", drum::START_BUTTON); - } - if (kit_state.select) - { - set_flag(buf, "select", drum::SELECT_BUTTON); - } - - // Unbound cause idk what to bind them to, but you don't really need them anyway. - // set_flag_if_any(buf, drum::SYSTEM_BUTTON, ); - // set_flag_if_any(buf, drum::BACK_BUTTON, ); -} - -bool rb3drums::KitState::is_cymbal() const -{ - return std::max({hihat, ride, crash}) >= midi::min_velocity(); -} - -bool rb3drums::KitState::is_drum() const -{ - return std::max({snare, hi_tom, low_tom, floor_tom}) >= midi::min_velocity(); -} - -void usb_device_rb3_midi_drums::ComboTracker::reload_definitions() -{ - m_definitions = { - {"start", g_cfg_rb3drums.combo_start.to_string(), [] - { - return drum::start_state(); - }}, - {"select", g_cfg_rb3drums.combo_select.to_string(), [] - { - return drum::select_state(); - }}, - {"hold kick", g_cfg_rb3drums.combo_toggle_hold_kick.to_string(), [] - { - return drum::toggle_hold_kick_state(); - }}}; -} - -void usb_device_rb3_midi_drums::ComboTracker::add(u8 note) -{ - if (!midi_notes.empty() && std::chrono::steady_clock::now() >= expiry) - { - // Combo expired. - reset(); - } - - const usz i = midi_notes.size(); - bool is_in_combo = false; - for (const auto& def : m_definitions) - { - if (i < def.notes.size() && note == def.notes[i]) - { - // Track notes as long as we match any combo. - midi_notes.push_back(note); - is_in_combo = true; - break; - } - } - - if (!is_in_combo) - { - reset(); - } - - if (midi_notes.size() == 1) - { - // New combo. - expiry = std::chrono::steady_clock::now() + midi::combo::window(); - } -} - -void usb_device_rb3_midi_drums::ComboTracker::reset() -{ - midi_notes.clear(); -} - -std::optional usb_device_rb3_midi_drums::ComboTracker::take_state() -{ - if (midi_notes.empty()) - { - return {}; - } - for (const auto& combo : m_definitions) - { - if (midi_notes == combo.notes) - { - rb3_midi_drums_log.success("hit combo: %s", combo.name); - reset(); - return combo.create_state(); - } - } - return {}; -} diff --git a/rpcs3/Emu/Io/RB3MidiDrums.h b/rpcs3/Emu/Io/RB3MidiDrums.h deleted file mode 100644 index 60a2874cef..0000000000 --- a/rpcs3/Emu/Io/RB3MidiDrums.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -#include -#include -#include -#include - -namespace rb3drums -{ - struct KitState - { - std::chrono::steady_clock::time_point expiry; - - u8 kick_pedal{}; - u8 hihat_pedal{}; - - u8 snare{}; - u8 snare_rim{}; - u8 hi_tom{}; - u8 low_tom{}; - u8 floor_tom{}; - - u8 hihat{}; - u8 ride{}; - u8 crash{}; - - // Buttons triggered by combos. - bool start{}; - bool select{}; - - // Special flag that keeps kick pedal held until toggled off. - // This is used in rb3 to access the category select dropdown in the song list. - bool toggle_hold_kick{}; - - bool is_cymbal() const; - bool is_drum() const; - }; - -} // namespace rb3drums - -namespace midi -{ - - enum class Id : u8 - { - // Each 'Note' can be triggered by multiple different numbers. - // Keeping them flattened in an enum for simplicity / switch statement usage. - - // These follow the rockband 3 midi pro adapter support. - Snare0 = 38, - Snare1 = 31, - Snare2 = 34, - Snare3 = 37, - Snare4 = 39, - HiTom0 = 48, - HiTom1 = 50, - LowTom0 = 45, - LowTom1 = 47, - FloorTom0 = 41, - FloorTom1 = 43, - Hihat0 = 22, - Hihat1 = 26, - Hihat2 = 42, - Hihat3 = 54, - Ride0 = 51, - Ride1 = 53, - Ride2 = 56, - Ride3 = 59, - Crash0 = 49, - Crash1 = 52, - Crash2 = 55, - Crash3 = 57, - Kick0 = 33, - Kick1 = 35, - Kick2 = 36, - HihatPedal = 44, - - // These are from alesis nitro mesh max. ymmv. - SnareRim = 40, // midi pro adapter counts this as snare. - HihatWithPedalUp = 46, // The midi pro adapter considers this a normal hihat hit. - HihatPedalPartial = 23, // If pedal is not 100% down, this will be sent instead of a normal hihat hit. - - // Internal value used for converting midi CC. - // Values past 127 are not used in midi notes. - MidiCC = 255, - }; - - // Intermediate mapping regardless of which midi ids triggered it. - enum class Note : u8 - { - Invalid, - Kick, - HihatPedal, - Snare, - SnareRim, - HiTom, - LowTom, - FloorTom, - HihatWithPedalUp, - Hihat, - Ride, - Crash, - }; - -} // namespace midi - -class usb_device_rb3_midi_drums : public usb_device_emulated -{ -public: - usb_device_rb3_midi_drums(const std::array& location, const std::string& device_name); - ~usb_device_rb3_midi_drums(); - - 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; - -private: - usz response_pos{}; - bool buttons_enabled{}; - RtMidiInPtr midi_in{}; - std::vector kit_states; - bool hold_kick{}; - bool midi_cc_triggered{}; - - struct Definition - { - std::string name; - std::vector notes; - std::function create_state; - - Definition(std::string name, const std::string_view csv, const std::function create_state); - }; - - class ComboTracker - { - public: - void reload_definitions(); - void add(u8 note); - void reset(); - std::optional take_state(); - - private: - std::chrono::steady_clock::time_point expiry; - std::vector midi_notes; - std::vector m_definitions; - }; - ComboTracker combo; - - std::unordered_map m_id_to_note_mapping; - - midi::Note id_to_note(midi::Id id); - rb3drums::KitState parse_midi_message(u8* msg, usz size); - rb3drums::KitState parse_midi_note(u8 id, u8 velocity); - bool is_midi_cc(u8 id, u8 value); - void write_state(u8* buf, const rb3drums::KitState&); -}; diff --git a/rpcs3/Emu/Io/RB3MidiGuitar.cpp b/rpcs3/Emu/Io/RB3MidiGuitar.cpp deleted file mode 100644 index 54654c24c1..0000000000 --- a/rpcs3/Emu/Io/RB3MidiGuitar.cpp +++ /dev/null @@ -1,372 +0,0 @@ -// Rock Band 3 MIDI Pro Adapter Emulator (Guitar Mode) - -#include "stdafx.h" -#include "RB3MidiGuitar.h" -#include "Emu/Cell/lv2/sys_usbd.h" - -LOG_CHANNEL(rb3_midi_guitar_log); - -usb_device_rb3_midi_guitar::usb_device_rb3_midi_guitar(const std::array& location, const std::string& device_name, bool twentytwo_fret) - : usb_device_emulated(location) -{ - // For the 22-fret guitar (Fender Squier), the only thing that's different - // is the device ID reported by the MIDI Pro Adapter. - // - // Everything else is *exactly* the same as the 17-fret guitar (Fender Mustang). - if (twentytwo_fret) - { - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0x00, 0x00, 0x00, 64, 0x12ba, 0x2538, 0x01, 0x01, 0x02, 0x00, 0x01}); - } - else - { - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0x00, 0x00, 0x00, 64, 0x12ba, 0x2438, 0x01, 0x01, 0x02, 0x00, 0x01}); - } - - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{41, 1, 1, 0, 0x80, 32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0, 0, 2, 3, 0, 0, 0})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 137})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0040, 10})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x0040, 10})); - - usb_device_emulated::add_string("Licensed by Sony Computer Entertainment America"); - usb_device_emulated::add_string("Harmonix RB3 MIDI Guitar Interface for PlayStation®3"); - - // connect to midi device - midi_in = rtmidi_in_create_default(); - ensure(midi_in); - - if (!midi_in->ok) - { - rb3_midi_guitar_log.error("Could not get MIDI in ptr: %s", midi_in->msg); - return; - } - - const RtMidiApi api = rtmidi_in_get_current_api(midi_in); - - if (!midi_in->ok) - { - rb3_midi_guitar_log.error("Could not get MIDI api: %s", midi_in->msg); - return; - } - - if (const char* api_name = rtmidi_api_name(api)) - { - rb3_midi_guitar_log.notice("Using %s api", api_name); - } - else - { - rb3_midi_guitar_log.warning("Could not get MIDI api name"); - } - - rtmidi_in_ignore_types(midi_in, false, true, true); - - const u32 port_count = rtmidi_get_port_count(midi_in); - - if (!midi_in->ok || port_count == umax) - { - rb3_midi_guitar_log.error("Could not get MIDI port count: %s", midi_in->msg); - return; - } - - for (u32 port_number = 0; port_number < port_count; port_number++) - { - char buf[128]{}; - s32 size = sizeof(buf); - if (rtmidi_get_port_name(midi_in, port_number, buf, &size) == -1 || !midi_in->ok) - { - rb3_midi_guitar_log.error("Error getting port name for port %d: %s", port_number, midi_in->msg); - return; - } - - rb3_midi_guitar_log.notice("Found device with name: %s", buf); - - if (device_name == buf) - { - rtmidi_open_port(midi_in, port_number, "RPCS3 MIDI Guitar Input"); - - if (!midi_in->ok) - { - rb3_midi_guitar_log.error("Could not open port %d for device '%s': %s", port_number, device_name, midi_in->msg); - return; - } - - rb3_midi_guitar_log.success("Connected to device: %s", device_name); - return; - } - } - - rb3_midi_guitar_log.error("Could not find device with name: %s", device_name); -} - -usb_device_rb3_midi_guitar::~usb_device_rb3_midi_guitar() -{ - rtmidi_in_free(midi_in); -} - -static const std::array disabled_response = { - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x26, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00}; - -static const std::array enabled_response = { - 0xe9, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x26, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00}; - -void usb_device_rb3_midi_guitar::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - - // configuration packets sent by rock band 3 - // we only really need to check 1 byte here to figure out if the game - // wants to enable midi data or disable it - if (bmRequestType == 0x21 && bRequest == 0x9 && wLength == 40) - { - if (buf_size < 3) - { - rb3_midi_guitar_log.warning("buffer size < 3, bailing out early (buf_size=0x%x)", buf_size); - return; - } - - switch (buf[2]) - { - case 0x89: - rb3_midi_guitar_log.notice("MIDI data enabled."); - buttons_enabled = true; - response_pos = 0; - break; - case 0x81: - rb3_midi_guitar_log.notice("MIDI data disabled."); - buttons_enabled = false; - response_pos = 0; - break; - default: - rb3_midi_guitar_log.warning("Unhandled SET_REPORT request: 0x%02X"); - break; - } - } - // the game expects some sort of response to the configuration packet - else if (bmRequestType == 0xa1 && bRequest == 0x1) - { - transfer->expected_count = buf_size; - if (buttons_enabled) - { - const usz remaining_bytes = enabled_response.size() - response_pos; - const usz copied_bytes = std::min(remaining_bytes, buf_size); - memcpy(buf, &enabled_response[response_pos], copied_bytes); - response_pos += copied_bytes; - } - else - { - const usz remaining_bytes = disabled_response.size() - response_pos; - const usz copied_bytes = std::min(remaining_bytes, buf_size); - memcpy(buf, &disabled_response[response_pos], copied_bytes); - response_pos += copied_bytes; - } - } - else if (bmRequestType == 0x21 && bRequest == 0x9 && wLength == 8) - { - // the game uses this request to do things like set the LEDs - // we don't have any LEDs, so do nothing - } - else - { - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - } -} - -void usb_device_rb3_midi_guitar::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; - // the real device takes 8ms to send a response, but there is - // no reason we can't make it faster - transfer->expected_time = get_timestamp() + 1'000; - - // default input state - const std::array bytes = { - 0x00, 0x00, 0x08, 0x80, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00}; - - if (buf_size < bytes.size()) - { - rb3_midi_guitar_log.warning("buffer size < %x, bailing out early (buf_size=0x%x)", bytes.size(), buf_size); - return; - } - - memcpy(buf, bytes.data(), bytes.size()); - - while (true) - { - u8 midi_msg[32]; - usz size = sizeof(midi_msg); - - // this returns a double as some sort of delta time, with -1.0 - // being used to signal an error - if (rtmidi_in_get_message(midi_in, midi_msg, &size) == -1.0) - { - rb3_midi_guitar_log.error("Error getting MIDI message: %s", midi_in->msg); - return; - } - - if (size == 0) - { - break; - } - - parse_midi_message(midi_msg, size); - } - - write_state(buf); -} - -void usb_device_rb3_midi_guitar::parse_midi_message(u8* msg, usz size) -{ - // this is not emulated correctly but the game doesn't seem to care - button_state.count++; - - // read frets - if (size == 8 && msg[0] == 0xF0 && msg[4] == 0x01) - { - switch (msg[5]) - { - case 1: - button_state.frets[0] = msg[6] - 0x40; - break; - case 2: - button_state.frets[1] = msg[6] - 0x3B; - break; - case 3: - button_state.frets[2] = msg[6] - 0x37; - break; - case 4: - button_state.frets[3] = msg[6] - 0x32; - break; - case 5: - button_state.frets[4] = msg[6] - 0x2D; - break; - case 6: - button_state.frets[5] = msg[6] - 0x28; - break; - default: - rb3_midi_guitar_log.warning("Invalid string for fret event: %d", msg[5]); - break; - } - } - - // read strings - if (size == 8 && msg[0] == 0xF0 && msg[4] == 0x05) - { - button_state.string_velocities[msg[5] - 1] = msg[6]; - } - - // read buttons - if (size == 10 && msg[0] == 0xF0 && msg[4] == 0x08) - { - button_state.dpad = msg[7] & 0x0f; - - button_state.square = (msg[5] & 0b0000'0001) == 0b0000'0001; - button_state.cross = (msg[5] & 0b0000'0010) == 0b0000'0010; - button_state.circle = (msg[5] & 0b0000'0100) == 0b0000'0100; - button_state.triangle = (msg[5] & 0b0000'1000) == 0b0000'1000; - - button_state.select = (msg[6] & 0b0000'0001) == 0b0000'0001; - button_state.start = (msg[6] & 0b0000'0010) == 0b0000'0010; - button_state.tilt_sensor = (msg[7] & 0b0100'0000) == 0b0100'0000; - } - - // sustain pedal - if (size == 3 && msg[0] == 0xB0 && msg[1] == 0x40) - { - button_state.sustain_pedal = msg[2] >= 40; - } -} - -void usb_device_rb3_midi_guitar::write_state(u8* buf) -{ - // encode frets - buf[8] |= (button_state.frets[0] & 0b11111) << 2; - buf[8] |= (button_state.frets[1] & 0b11000) >> 3; - buf[7] |= (button_state.frets[1] & 0b00111) << 5; - buf[7] |= (button_state.frets[2] & 0b11111) >> 0; - buf[6] |= (button_state.frets[3] & 0b11111) << 2; - buf[6] |= (button_state.frets[4] & 0b11000) >> 3; - buf[5] |= (button_state.frets[4] & 0b00111) << 5; - buf[5] |= (button_state.frets[5] & 0b11111) >> 0; - - // encode strings - buf[14] = button_state.string_velocities[0]; - buf[13] = button_state.string_velocities[1]; - buf[12] = button_state.string_velocities[2]; - buf[11] = button_state.string_velocities[3]; - buf[10] = button_state.string_velocities[4]; - buf[9] = button_state.string_velocities[5]; - - // encode frets for playing 5 fret on the pro guitar - // this actually isn't done by the real MPA, but Rock Band 3 allows this - // so there's no harm in supporting it. - for (u8 i : button_state.frets) - { - switch (i) - { - case 1: - case 6: - case 13: - buf[9] |= 0b1000'0000; - break; - case 2: - case 7: - case 14: - buf[10] |= 0b1000'0000; - break; - case 3: - case 8: - case 15: - buf[11] |= 0b1000'0000; - break; - case 4: - case 9: - case 16: - buf[12] |= 0b1000'0000; - break; - case 5: - case 10: - case 17: - buf[13] |= 0b1000'0000; - break; - default: - break; - } - - // enable the solo bit for frets >= 13 - if (i >= 13) - { - buf[8] |= 0b1000'0000; - } - } - - // encode tilt sensor/sustain_pedal - if (button_state.tilt_sensor || button_state.sustain_pedal) - { - buf[15] = 0x7f; - buf[16] = 0x7f; - buf[17] = 0x7f; - } - - buf[1] |= 0b0000'0001 * button_state.select; - buf[1] |= 0b0000'0010 * button_state.start; - - buf[0] |= 0b0000'0010 * button_state.cross; - buf[0] |= 0b0000'0100 * button_state.circle; - buf[0] |= 0b0000'1000 * button_state.triangle; - buf[0] |= 0b0000'0001 * button_state.square; - - buf[2] = button_state.dpad; -} diff --git a/rpcs3/Emu/Io/RB3MidiGuitar.h b/rpcs3/Emu/Io/RB3MidiGuitar.h deleted file mode 100644 index 3a93f95d61..0000000000 --- a/rpcs3/Emu/Io/RB3MidiGuitar.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -#include - -class usb_device_rb3_midi_guitar : public usb_device_emulated -{ -private: - usz response_pos = 0; - bool buttons_enabled = false; - RtMidiInPtr midi_in{}; - - // button states - struct - { - u8 count = 0; - - bool cross = false; - bool circle = false; - bool square = false; - bool triangle = false; - - bool start = false; - bool select = false; - bool tilt_sensor = false; - bool sustain_pedal = false; // used for overdrive - - u8 dpad = 8; - - std::array frets{}; - std::array string_velocities{}; - } button_state; - - void parse_midi_message(u8* msg, usz size); - void write_state(u8* buf); - -public: - usb_device_rb3_midi_guitar(const std::array& location, const std::string& device_name, bool twentytwo_fret); - ~usb_device_rb3_midi_guitar(); - - 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/Emu/Io/RB3MidiKeyboard.cpp b/rpcs3/Emu/Io/RB3MidiKeyboard.cpp deleted file mode 100644 index ccfc2dbdc8..0000000000 --- a/rpcs3/Emu/Io/RB3MidiKeyboard.cpp +++ /dev/null @@ -1,357 +0,0 @@ -// Rock Band 3 MIDI Pro Adapter Emulator (Keyboard Mode) - -#include "stdafx.h" -#include "RB3MidiKeyboard.h" -#include "Emu/Cell/lv2/sys_usbd.h" - -LOG_CHANNEL(rb3_midi_keyboard_log); - -usb_device_rb3_midi_keyboard::usb_device_rb3_midi_keyboard(const std::array& location, const std::string& device_name) - : usb_device_emulated(location) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0x00, 0x00, 0x00, 64, 0x12ba, 0x2338, 0x01, 0x01, 0x02, 0x00, 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{41, 1, 1, 0, 0x80, 32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0, 0, 2, 3, 0, 0, 0})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 137})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0040, 10})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x0040, 10})); - - usb_device_emulated::add_string("Licensed by Sony Computer Entertainment America"); - usb_device_emulated::add_string("Harmonix RB3 MIDI Keyboard Interface for PlayStation®3"); - - // connect to midi device - midi_in = rtmidi_in_create_default(); - ensure(midi_in); - - if (!midi_in->ok) - { - rb3_midi_keyboard_log.error("Could not get MIDI in ptr: %s", midi_in->msg); - return; - } - - const RtMidiApi api = rtmidi_in_get_current_api(midi_in); - - if (!midi_in->ok) - { - rb3_midi_keyboard_log.error("Could not get MIDI api: %s", midi_in->msg); - return; - } - - if (const char* api_name = rtmidi_api_name(api)) - { - rb3_midi_keyboard_log.notice("Using %s api", api_name); - } - else - { - rb3_midi_keyboard_log.warning("Could not get MIDI api name"); - } - - const u32 port_count = rtmidi_get_port_count(midi_in); - - if (!midi_in->ok || port_count == umax) - { - rb3_midi_keyboard_log.error("Could not get MIDI port count: %s", midi_in->msg); - return; - } - - for (u32 port_number = 0; port_number < port_count; port_number++) - { - char buf[128]{}; - s32 size = sizeof(buf); - if (rtmidi_get_port_name(midi_in, port_number, buf, &size) == -1 || !midi_in->ok) - { - rb3_midi_keyboard_log.error("Error getting port name for port %d: %s", port_number, midi_in->msg); - return; - } - - rb3_midi_keyboard_log.notice("Found device with name: %s", buf); - - if (device_name == buf) - { - rtmidi_open_port(midi_in, port_number, "RPCS3 MIDI Keyboard Input"); - - if (!midi_in->ok) - { - rb3_midi_keyboard_log.error("Could not open port %d for device '%s': %s", port_number, device_name, midi_in->msg); - return; - } - - rb3_midi_keyboard_log.success("Connected to device: %s", device_name); - return; - } - } - - rb3_midi_keyboard_log.error("Could not find device with name: %s", device_name); -} - -usb_device_rb3_midi_keyboard::~usb_device_rb3_midi_keyboard() -{ - rtmidi_in_free(midi_in); -} - -static const std::array disabled_response = { - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x26, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00}; - -static const std::array enabled_response = { - 0xe9, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x26, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00}; - -void usb_device_rb3_midi_keyboard::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - - // configuration packets sent by rock band 3 - // we only really need to check 1 byte here to figure out if the game - // wants to enable midi data or disable it - if (bmRequestType == 0x21 && bRequest == 0x9 && wLength == 40) - { - if (buf_size < 3) - { - rb3_midi_keyboard_log.warning("buffer size < 3, bailing out early (buf_size=0x%x)", buf_size); - return; - } - - switch (buf[2]) - { - case 0x89: - rb3_midi_keyboard_log.notice("MIDI data enabled."); - buttons_enabled = true; - response_pos = 0; - break; - case 0x81: - rb3_midi_keyboard_log.notice("MIDI data disabled."); - buttons_enabled = false; - response_pos = 0; - break; - default: - rb3_midi_keyboard_log.warning("Unhandled SET_REPORT request: 0x%02X"); - break; - } - } - // the game expects some sort of response to the configuration packet - else if (bmRequestType == 0xa1 && bRequest == 0x1) - { - transfer->expected_count = buf_size; - if (buttons_enabled) - { - const usz remaining_bytes = enabled_response.size() - response_pos; - const usz copied_bytes = std::min(remaining_bytes, buf_size); - memcpy(buf, &enabled_response[response_pos], copied_bytes); - response_pos += copied_bytes; - } - else - { - const usz remaining_bytes = disabled_response.size() - response_pos; - const usz copied_bytes = std::min(remaining_bytes, buf_size); - memcpy(buf, &disabled_response[response_pos], copied_bytes); - response_pos += copied_bytes; - } - } - else if (bmRequestType == 0x21 && bRequest == 0x9 && wLength == 8) - { - // the game uses this request to do things like set the LEDs - // we don't have any LEDs, so do nothing - } - else - { - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - } -} - -void usb_device_rb3_midi_keyboard::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; - // the real device takes 8ms to send a response, but there is - // no reason we can't make it faster - transfer->expected_time = get_timestamp() + 1'000; - - // default input state - static const std::array bytes = { - 0x00, 0x00, 0x08, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02}; - - if (buf_size < bytes.size()) - { - rb3_midi_keyboard_log.warning("buffer size < %x, bailing out early (buf_size=0x%x)", bytes.size(), buf_size); - return; - } - - memcpy(buf, bytes.data(), bytes.size()); - - while (true) - { - u8 midi_msg[32]; - usz size = sizeof(midi_msg); - - // this returns a double as some sort of delta time, with -1.0 - // being used to signal an error - if (rtmidi_in_get_message(midi_in, midi_msg, &size) == -1.0) - { - rb3_midi_keyboard_log.error("Error getting MIDI message: %s", midi_in->msg); - return; - } - - if (size == 0) - { - break; - } - - parse_midi_message(midi_msg, size); - } - - write_state(buf); -} - -void usb_device_rb3_midi_keyboard::parse_midi_message(u8* msg, usz size) -{ - // this is not emulated correctly but the game doesn't seem to care - button_state.count++; - - // handle note on/off messages - if (size == 3 && (msg[0] == 0x80 || msg[0] == 0x90)) - { - const bool note_on = (0x10 & msg[0]) == 0x10 && msg[2] != 0; - - // handle navigation buttons - switch (msg[1]) - { - case 44: // G#2 - button_state.cross = note_on; - break; - case 42: // F#2 - button_state.circle = note_on; - break; - case 39: // D#2 - button_state.square = note_on; - break; - case 37: // C#2 - button_state.triangle = note_on; - break; - case 46: // A#2 - button_state.start = note_on; - break; - case 36: // C2 - button_state.select = note_on; - break; - case 45: // A2 - button_state.overdrive = note_on; - break; - case 41: // F2 - button_state.dpad_up = note_on; - break; - case 43: // G2 - button_state.dpad_down = note_on; - break; - case 38: // D2 - button_state.dpad_left = note_on; - break; - case 40: // E2 - button_state.dpad_right = note_on; - break; - default: - break; - } - - // handle keyboard keys - if (msg[1] >= 48 && msg[1] <= (48 + button_state.keys.size())) - { - const u32 key = msg[1] - 48; - button_state.keys[key] = note_on; - button_state.velocities[key] = msg[2]; - } - } - - // control channel for overdrive - else if (size == 3 && msg[0] == 0xB0) - { - switch (msg[1]) - { - case 0x1: - case 0x40: - button_state.overdrive = msg[2] > 40; - break; - default: - break; - } - } - - // pitch wheel - else if (size == 3 && msg[0] == 0xE0) - { - const u16 msb = msg[2]; - const u16 lsb = msg[1]; - button_state.pitch_wheel = (msb << 7) | lsb; - } -} - -void usb_device_rb3_midi_keyboard::write_state(u8* buf) -{ - // buttons - buf[0] |= 0b0000'0010 * button_state.cross; - buf[0] |= 0b0000'0100 * button_state.circle; - buf[0] |= 0b0000'0001 * button_state.square; - buf[0] |= 0b0000'1000 * button_state.triangle; - buf[1] |= 0b0000'0010 * button_state.start; - buf[1] |= 0b0000'0001 * button_state.select; - - // dpad - if (button_state.dpad_up) - { - buf[2] = 0; - } - else if (button_state.dpad_down) - { - buf[2] = 4; - } - else if (button_state.dpad_left) - { - buf[2] = 6; - } - else if (button_state.dpad_right) - { - buf[2] = 2; - } - - // build key bitfield and write velocities - u32 key_mask = 0; - u8 vel_idx = 0; - - for (usz i = 0; i < button_state.keys.size(); i++) - { - key_mask <<= 1; - key_mask |= 0x1 * button_state.keys[i]; - - // the keyboard can only report 5 velocities from left to right - if (button_state.keys[i] && vel_idx < 5) - { - buf[8 + vel_idx++] = button_state.velocities[i]; - } - } - - // write keys - buf[5] = (key_mask >> 17) & 0xff; - buf[6] = (key_mask >> 9) & 0xff; - buf[7] = (key_mask >> 1) & 0xff; - buf[8] |= 0b1000'0000 * (key_mask & 0x1); - - // overdrive - buf[13] |= 0b1000'0000 * button_state.overdrive; - - // pitch wheel - const u8 wheel_pos = std::abs((button_state.pitch_wheel >> 6) - 0x80); - if (wheel_pos >= 5) - { - buf[15] = std::min(std::max(0x5, wheel_pos), 0x75); - } -} diff --git a/rpcs3/Emu/Io/RB3MidiKeyboard.h b/rpcs3/Emu/Io/RB3MidiKeyboard.h deleted file mode 100644 index c5042af239..0000000000 --- a/rpcs3/Emu/Io/RB3MidiKeyboard.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -#include - -class usb_device_rb3_midi_keyboard : public usb_device_emulated -{ -private: - usz response_pos = 0; - bool buttons_enabled = false; - RtMidiInPtr midi_in{}; - - // button states - // TODO: emulate velocity - struct - { - u8 count = 0; - - bool cross = false; - bool circle = false; - bool square = false; - bool triangle = false; - - bool start = false; - bool select = false; - bool overdrive = false; - - bool dpad_up = false; - bool dpad_down = false; - bool dpad_left = false; - bool dpad_right = false; - - std::array keys{}; - std::array velocities{}; - - s16 pitch_wheel = 0; - } button_state; - - void parse_midi_message(u8* msg, usz size); - void write_state(u8* buf); - -public: - usb_device_rb3_midi_keyboard(const std::array& location, const std::string& device_name); - ~usb_device_rb3_midi_keyboard(); - - 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/Emu/Io/Skylander.cpp b/rpcs3/Emu/Io/Skylander.cpp deleted file mode 100644 index ff9d9bf3e2..0000000000 --- a/rpcs3/Emu/Io/Skylander.cpp +++ /dev/null @@ -1,374 +0,0 @@ -#include "stdafx.h" -#include "Skylander.h" -#include "Emu/Cell/lv2/sys_usbd.h" - -LOG_CHANNEL(skylander_log, "skylander"); - -sky_portal g_skyportal; - -void skylander::save() -{ - if (!sky_file) - { - skylander_log.error("Tried to save skylander to file but no skylander is active!"); - return; - } - - { - sky_file.seek(0, fs::seek_set); - sky_file.write(data.data(), 0x40 * 0x10); - } -} - -void sky_portal::activate() -{ - std::lock_guard lock(sky_mutex); - if (activated) - { - // If the portal was already active no change is needed - return; - } - - // If not we need to advertise change to all the figures present on the portal - for (auto& s : skylanders) - { - if (s.status & 1) - { - s.queued_status.push(3); - s.queued_status.push(1); - } - } - - activated = true; -} - -void sky_portal::deactivate() -{ - std::lock_guard lock(sky_mutex); - - for (auto& s : skylanders) - { - // check if at the end of the updates there would be a figure on the portal - if (!s.queued_status.empty()) - { - s.status = s.queued_status.back(); - s.queued_status = std::queue(); - } - - s.status &= 1; - } - - activated = false; -} - -void sky_portal::set_leds(u8 r, u8 g, u8 b) -{ - std::lock_guard lock(sky_mutex); - this->r = r; - this->g = g; - this->b = b; -} - -void sky_portal::get_status(u8* reply_buf) -{ - std::lock_guard lock(sky_mutex); - - u16 status = 0; - - for (int i = 7; i >= 0; i--) - { - auto& s = skylanders[i]; - - if (!s.queued_status.empty()) - { - s.status = s.queued_status.front(); - s.queued_status.pop(); - } - - status <<= 2; - status |= s.status; - } - - std::memset(reply_buf, 0, 0x20); - reply_buf[0] = 0x53; - write_to_ptr>(reply_buf, 1, status); - reply_buf[5] = interrupt_counter++; - reply_buf[6] = 0x01; -} - -void sky_portal::query_block(u8 sky_num, u8 block, u8* reply_buf) -{ - std::lock_guard lock(sky_mutex); - - const auto& thesky = skylanders[sky_num]; - - reply_buf[0] = 'Q'; - reply_buf[2] = block; - if (thesky.status & 1) - { - reply_buf[1] = (0x10 | sky_num); - memcpy(reply_buf + 3, thesky.data.data() + (16 * block), 16); - } - else - { - reply_buf[1] = sky_num; - } -} - -void sky_portal::write_block(u8 sky_num, u8 block, const u8* to_write_buf, u8* reply_buf) -{ - std::lock_guard lock(sky_mutex); - - auto& thesky = skylanders[sky_num]; - - reply_buf[0] = 'W'; - reply_buf[2] = block; - - if (thesky.status & 1) - { - reply_buf[1] = (0x10 | sky_num); - memcpy(thesky.data.data() + (block * 16), to_write_buf, 16); - thesky.save(); - } - else - { - reply_buf[1] = sky_num; - } -} - -bool sky_portal::remove_skylander(u8 sky_num) -{ - std::lock_guard lock(sky_mutex); - auto& thesky = skylanders[sky_num]; - - if (thesky.status & 1) - { - thesky.status = 2; - thesky.queued_status.push(2); - thesky.queued_status.push(0); - thesky.sky_file.close(); - return true; - } - - return false; -} - -u8 sky_portal::load_skylander(u8* buf, fs::file in_file) -{ - std::lock_guard lock(sky_mutex); - - const u32 sky_serial = read_from_ptr>(buf); - u8 found_slot = 0xFF; - - // mimics spot retaining on the portal - for (u8 i = 0; i < 8; i++) - { - if ((skylanders[i].status & 1) == 0) - { - if (skylanders[i].last_id == sky_serial) - { - found_slot = i; - break; - } - - if (i < found_slot) - { - found_slot = i; - } - } - } - - ensure(found_slot != 0xFF); - - skylander& thesky = skylanders[found_slot]; - memcpy(thesky.data.data(), buf, thesky.data.size()); - thesky.sky_file = std::move(in_file); - thesky.status = 3; - thesky.queued_status.push(3); - thesky.queued_status.push(1); - thesky.last_id = sky_serial; - - return found_slot; -} - -usb_device_skylander::usb_device_skylander(const std::array& location) - : usb_device_emulated(location) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0x00, 0x00, 0x00, 0x40, 0x1430, 0x0150, 0x0100, 0x01, 0x02, 0x00, 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x0029, 0x01, 0x01, 0x00, 0x80, 0xFA})); - 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, 0x40, 0x01})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x40, 0x01})); -} - -usb_device_skylander::~usb_device_skylander() -{ -} - -std::shared_ptr usb_device_skylander::make_instance(u32, const std::array& location) -{ - return std::make_shared(location); -} - -u16 usb_device_skylander::get_num_emu_devices() -{ - return 1; -} - -void usb_device_skylander::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) - { - // HID Host 2 Device - case 0x21: - switch (bRequest) - { - case 0x09: - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - // 100 usec, control transfers are very fast - transfer->expected_time = get_timestamp() + 100; - - std::array q_result = {}; - - switch (buf[0]) - { - case 'A': - { - // Activate command - ensure(buf_size == 2 || buf_size == 32); - q_result = {0x41, buf[1], 0xFF, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00}; - q_queries.push(q_result); - g_skyportal.activate(); - break; - } - case 'C': - { - // Set LEDs colour - ensure(buf_size == 4 || buf_size == 32); - g_skyportal.set_leds(buf[1], buf[2], buf[3]); - break; - } - case 'J': - { - // Sync status from game? - ensure(buf_size == 7); - q_result[0] = 0x4A; - q_queries.push(q_result); - break; - } - case 'L': - { - // Trap Team Portal Side Lights - ensure(buf_size == 5); - // TODO Proper Light side structs - break; - } - case 'M': - { - // Audio Firmware version - // Return version of 0 to prevent attempts to - // play audio on the portal - ensure(buf_size == 2); - q_result = {0x4D, buf[1], 0x00, 0x19}; - q_queries.push(q_result); - break; - } - case 'Q': - { - // Queries a block - ensure(buf_size == 3 || buf_size == 32); - - const u8 sky_num = buf[1] & 0xF; - ensure(sky_num < 8); - const u8 block = buf[2]; - ensure(block < 0x40); - - g_skyportal.query_block(sky_num, block, q_result.data()); - q_queries.push(q_result); - break; - } - case 'R': - { - // Shutdowns the portal - ensure(buf_size == 2 || buf_size == 32); - q_result = { - 0x52, 0x02, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - q_queries.push(q_result); - g_skyportal.deactivate(); - break; - } - case 'S': - { - // ? - ensure(buf_size == 1 || buf_size == 32); - break; - } - case 'V': - { - // ? - ensure(buf_size == 4); - break; - } - case 'W': - { - // Writes a block - ensure(buf_size == 19 || buf_size == 32); - - const u8 sky_num = buf[1] & 0xF; - ensure(sky_num < 8); - const u8 block = buf[2]; - ensure(block < 0x40); - - g_skyportal.write_block(sky_num, block, &buf[3], q_result.data()); - q_queries.push(q_result); - break; - } - default: - skylander_log.error("Unhandled Query: buf_size=0x%02X, Type=0x%02X, bRequest=0x%02X, bmRequestType=0x%02X", buf_size, (buf_size > 0) ? buf[0] : -1, bRequest, bmRequestType); - break; - } - break; - } - break; - default: - // Follow to default emulated handler - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - break; - } -} - -void usb_device_skylander::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) -{ - ensure(buf_size == 0x20); - - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - - if (endpoint == 0x02) - { - // Audio transfers are fairly quick(~1ms) - transfer->expected_time = get_timestamp() + 1000; - // The response is simply the request, echoed back - } - else - { - // Interrupt transfers are slow(~22ms) - transfer->expected_time = get_timestamp() + 22000; - if (!q_queries.empty()) - { - memcpy(buf, q_queries.front().data(), 0x20); - q_queries.pop(); - } - else - { - g_skyportal.get_status(buf); - } - } -} diff --git a/rpcs3/Emu/Io/Skylander.h b/rpcs3/Emu/Io/Skylander.h deleted file mode 100644 index 436f566ef0..0000000000 --- a/rpcs3/Emu/Io/Skylander.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" -#include "util/mutex.h" -#include - -struct skylander -{ - fs::file sky_file; - u8 status = 0; - std::queue queued_status; - std::array data{}; - u32 last_id = 0; - void save(); -}; - -class sky_portal -{ -public: - void activate(); - void deactivate(); - void set_leds(u8 r, u8 g, u8 b); - - void get_status(u8* buf); - void query_block(u8 sky_num, u8 block, u8* reply_buf); - void write_block(u8 sky_num, u8 block, const u8* to_write_buf, u8* reply_buf); - - bool remove_skylander(u8 sky_num); - u8 load_skylander(u8* buf, fs::file in_file); - -protected: - shared_mutex sky_mutex; - - bool activated = true; - u8 interrupt_counter = 0; - u8 r = 0, g = 0, b = 0; - - skylander skylanders[8]; -}; - -extern sky_portal g_skyportal; - -class usb_device_skylander : public usb_device_emulated -{ -public: - usb_device_skylander(const std::array& location); - ~usb_device_skylander(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - -protected: - std::queue> q_queries; -}; diff --git a/rpcs3/Emu/Io/TopShotElite.cpp b/rpcs3/Emu/Io/TopShotElite.cpp deleted file mode 100644 index fa87a47747..0000000000 --- a/rpcs3/Emu/Io/TopShotElite.cpp +++ /dev/null @@ -1,398 +0,0 @@ -#include "stdafx.h" -#include "TopShotElite.h" -#include "MouseHandler.h" -#include "Emu/IdManager.h" -#include "Emu/Io/topshotelite_config.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/system_config.h" -#include "Input/pad_thread.h" - -LOG_CHANNEL(topshotelite_log); - -#define TSE_CALIB_LOG false -// 0 < Calib_Top < Calib_Bottom < 0x2ff -// 0 < Calib_Right < Calib_Left < 0x3ff -constexpr u16 TSE_CALIB_TOP = 20; -constexpr u16 TSE_CALIB_BOTTOM = 840; -constexpr u16 TSE_CALIB_LEFT = 930; -constexpr u16 TSE_CALIB_RIGHT = 95; -constexpr u16 TSE_CALIB_DIST = 95; - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](topshotelite_btn value) - { - switch (value) - { - case topshotelite_btn::trigger: return "Trigger"; - case topshotelite_btn::reload: return "Reload"; - case topshotelite_btn::square: return "Square"; - case topshotelite_btn::cross: return "Cross"; - case topshotelite_btn::circle: return "Circle"; - case topshotelite_btn::triangle: return "Triangle"; - case topshotelite_btn::select: return "Select"; - case topshotelite_btn::start: return "Start"; - case topshotelite_btn::l3: return "L3"; - case topshotelite_btn::r3: return "R3"; - case topshotelite_btn::ps: return "PS"; - case topshotelite_btn::dpad_up: return "D-Pad Up"; - case topshotelite_btn::dpad_down: return "D-Pad Down"; - case topshotelite_btn::dpad_left: return "D-Pad Left"; - case topshotelite_btn::dpad_right: return "D-Pad Right"; - case topshotelite_btn::ls_x: return "Left Stick X-Axis"; - case topshotelite_btn::ls_y: return "Left Stick Y-Axis"; - case topshotelite_btn::rs_x: return "Right Stick X-Axis"; - case topshotelite_btn::rs_y: return "Right Stick Y-Axis"; - case topshotelite_btn::count: return "Count"; - } - - return unknown; - }); -} - -#pragma pack(push, 1) -struct TopShotElite_data -{ - uint8_t btn_square : 1; - uint8_t btn_cross : 1; - uint8_t btn_circle : 1; - uint8_t btn_triangle : 1; - uint8_t btn_reload : 1; - uint8_t btn_trigger : 1; - uint8_t : 2; - - uint8_t btn_select : 1; - uint8_t btn_start : 1; - uint8_t btn_l3 : 1; - uint8_t btn_r3 : 1; - uint8_t btn_ps : 1; - uint8_t : 3; - - uint8_t dpad; - uint8_t stick_lx; - uint8_t stick_ly; - uint8_t stick_rx; - uint8_t stick_ry; - - uint8_t led_lx_hi : 8; - uint8_t led_ly_hi : 6; - uint8_t led_lx_lo : 2; - uint8_t detect_l : 4; - uint8_t led_ly_lo : 4; - - uint8_t led_rx_hi : 8; - uint8_t led_ry_hi : 6; - uint8_t led_rx_lo : 2; - uint8_t detect_r : 4; - uint8_t led_ry_lo : 4; - - uint8_t : 8; - uint8_t : 8; - uint8_t : 8; - - uint8_t trigger; - uint8_t : 8; - uint8_t : 8; - uint16_t unk[4]; -}; -#pragma pack(pop) - -enum -{ - Dpad_North, - Dpad_NE, - Dpad_East, - Dpad_SE, - Dpad_South, - Dpad_SW, - Dpad_West, - Dpad_NW, - Dpad_None = 0x0f -}; - -usb_device_topshotelite::usb_device_topshotelite(u32 controller_index, const std::array& location) - : usb_device_emulated(location), m_controller_index(controller_index), m_mode(0) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0100, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x20, - .idVendor = 0x12ba, - .idProduct = 0x04a0, - .bcdDevice = 0x0108, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - .bNumConfigurations = 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 0x0029, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0x80, - .bMaxPower = 0x32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x02, - .bInterfaceClass = 0x03, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, - .iInterface = 0x00})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, - UsbDeviceHID{ - .bcdHID = 0x0110, - .bCountryCode = 0x00, - .bNumDescriptors = 0x01, - .bDescriptorType = 0x22, - .wDescriptorLength = 0x0089})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x81, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0040, - .bInterval = 0x0a})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x02, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0040, - .bInterval = 0x0a})); - - add_string("GuitarHero for Playstation (R) 3"); - add_string("GuitarHero for Playstation (R) 3"); -} - -usb_device_topshotelite::~usb_device_topshotelite() -{ -} - -void usb_device_topshotelite::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 100; - - switch (bmRequestType) - { - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE: // 0x21 - switch (bRequest) - { - case 0x09: // SET_REPORT - ensure(buf_size >= 8); - switch (buf[0]) - { - case 0x01: - topshotelite_log.trace("Leds: %s/%s/%s/%s", - buf[2] & 1 ? "ON" : "OFF", - buf[2] & 2 ? "ON" : "OFF", - buf[2] & 4 ? "ON" : "OFF", - buf[2] & 8 ? "ON" : "OFF"); - break; - case 0x82: - m_mode = buf[2]; - break; - default: - topshotelite_log.error("Unhandled SET_REPORT packet : %x", buf[0]); - break; - } - break; - default: - topshotelite_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest); - break; - } - break; - default: - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - break; - } -} - -extern bool is_input_allowed(); - -static void set_sensor_pos(struct TopShotElite_data* ts, s32 led_lx, s32 led_ly, s32 led_rx, s32 led_ry, s32 detect_l, s32 detect_r) -{ - ts->led_lx_hi = led_lx >> 2; - ts->led_lx_lo = led_lx & 0x3; - ts->led_ly_hi = led_ly >> 4; - ts->led_ly_lo = led_ly & 0xf; - - ts->led_rx_hi = led_rx >> 2; - ts->led_rx_lo = led_rx & 0x3; - ts->led_ry_hi = led_ry >> 4; - ts->led_ry_lo = led_ry & 0xf; - - ts->detect_l = detect_l; - ts->detect_r = detect_r; -} - -static void prepare_data(const TopShotElite_data* ts, u8* data) -{ - std::memcpy(data, ts, sizeof(TopShotElite_data)); - topshotelite_log.trace("interrupt_transfer: %s", fmt::buf_to_hexstring(data, sizeof(TopShotElite_data))); -} - -void usb_device_topshotelite::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer) -{ - ensure(buf_size >= sizeof(TopShotElite_data)); - - transfer->fake = true; - transfer->expected_count = sizeof(TopShotElite_data); - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 4000; - - struct TopShotElite_data ts{}; - ts.dpad = Dpad_None; - ts.stick_lx = ts.stick_ly = ts.stick_rx = ts.stick_ry = 0x7f; - if (m_mode) - { - set_sensor_pos(&ts, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0xf, 0xf); - } - ts.unk[0] = ts.unk[1] = ts.unk[2] = ts.unk[3] = 0x0200; - - if (!is_input_allowed()) - { - prepare_data(&ts, buf); - return; - } - - if (g_cfg.io.mouse == mouse_handler::null) - { - topshotelite_log.warning("Top Shot Elite requires a Mouse Handler enabled"); - prepare_data(&ts, buf); - return; - } - - if (m_controller_index >= g_cfg_topshotelite.players.size()) - { - topshotelite_log.warning("Top Shot Fearmaster controllers are only supported for Player1 to Player%d", g_cfg_topshotelite.players.size()); - prepare_data(&ts, buf); - return; - } - - bool up = false, right = false, down = false, left = false; - const auto input_callback = [&ts, &up, &down, &left, &right](topshotelite_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; - - switch (btn) - { - case topshotelite_btn::trigger: ts.btn_trigger |= 1; break; - case topshotelite_btn::reload: ts.btn_reload |= 1; break; - case topshotelite_btn::square: ts.btn_square |= 1; break; - case topshotelite_btn::cross: ts.btn_cross |= 1; break; - case topshotelite_btn::circle: ts.btn_circle |= 1; break; - case topshotelite_btn::triangle: ts.btn_triangle |= 1; break; - case topshotelite_btn::select: ts.btn_select |= 1; break; - case topshotelite_btn::start: ts.btn_start |= 1; break; - case topshotelite_btn::l3: ts.btn_l3 |= 1; break; - case topshotelite_btn::r3: ts.btn_r3 |= 1; break; - case topshotelite_btn::ps: ts.btn_ps |= 1; break; - case topshotelite_btn::dpad_up: up = true; break; - case topshotelite_btn::dpad_down: down = true; break; - case topshotelite_btn::dpad_left: left = true; break; - case topshotelite_btn::dpad_right: right = true; break; - case topshotelite_btn::ls_x: ts.stick_lx = static_cast(value); break; - // you know you have a «Top» controller when the games are programmed to ignore a perfect controller, so we have to simulate a drift - case topshotelite_btn::ls_y: ts.stick_ly = std::min(0xff, 1 + static_cast(value)); break; - case topshotelite_btn::rs_x: ts.stick_rx = static_cast(value); break; - case topshotelite_btn::rs_y: ts.stick_ry = static_cast(value); break; - case topshotelite_btn::count: break; - } - }; - - const auto& cfg = ::at32(g_cfg_topshotelite.players, m_controller_index); - - { - std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_pad_thread(); - const auto& pads = gamepad_handler->GetPads(); - const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) - { - cfg->handle_input(pad, true, input_callback); - } - } - - if (!up && !right && !down && !left) - ts.dpad = Dpad_None; - else if (up && !left && !right) - ts.dpad = Dpad_North; - else if (up && right) - ts.dpad = Dpad_NE; - else if (right && !up && !down) - ts.dpad = Dpad_East; - else if (down && right) - ts.dpad = Dpad_SE; - else if (down && !left && !right) - ts.dpad = Dpad_South; - else if (down && left) - ts.dpad = Dpad_SW; - else if (left && !up && !down) - ts.dpad = Dpad_West; - else if (up && left) - ts.dpad = Dpad_NW; - - if (m_mode) - { - auto& mouse_handler = g_fxo->get(); - std::lock_guard mouse_lock(mouse_handler.mutex); - - mouse_handler.Init(4); - - const u32 mouse_index = g_cfg.io.mouse == mouse_handler::basic ? 0 : m_controller_index; - if (mouse_index >= mouse_handler.GetMice().size()) - { - prepare_data(&ts, buf); - return; - } - - const Mouse& mouse_data = ::at32(mouse_handler.GetMice(), mouse_index); - cfg->handle_input(mouse_data, input_callback); - ts.trigger = ts.btn_trigger ? 0xff : 0x00; - - if (mouse_data.x_max <= 0 || mouse_data.y_max <= 0) - { - prepare_data(&ts, buf); - return; - } - - s32 led_lx = 0x3ff - (TSE_CALIB_RIGHT + (mouse_data.x_pos * (TSE_CALIB_LEFT - TSE_CALIB_RIGHT) / mouse_data.x_max) + TSE_CALIB_DIST); - s32 led_rx = 0x3ff - (TSE_CALIB_RIGHT + (mouse_data.x_pos * (TSE_CALIB_LEFT - TSE_CALIB_RIGHT) / mouse_data.x_max) - TSE_CALIB_DIST); - - s32 led_ly = TSE_CALIB_TOP + (mouse_data.y_pos * (TSE_CALIB_BOTTOM - TSE_CALIB_TOP) / mouse_data.y_max); - s32 led_ry = TSE_CALIB_TOP + (mouse_data.y_pos * (TSE_CALIB_BOTTOM - TSE_CALIB_TOP) / mouse_data.y_max); - - u8 detect_l = 0x2, detect_r = 0x2; // 0x2 = led detected / 0xf = undetected - - if (led_lx < 0 || led_lx > 0x3ff || led_ly < 0 || led_ly > 0x3ff) - { - led_lx = 0x3ff; - led_ly = 0x3ff; - detect_l = 0xf; - } - - if (led_rx < 0 || led_rx > 0x3ff || led_ry < 0 || led_ry > 0x3ff) - { - led_rx = 0x3ff; - led_ry = 0x3ff; - detect_r = 0xf; - } - - set_sensor_pos(&ts, led_lx, led_ly, led_rx, led_ry, detect_l, detect_r); - -#if TSE_CALIB_LOG - topshotelite_log.error("L: %d x %d, R: %d x %d", led_lx + TSE_CALIB_DIST, led_ly, led_rx - TSE_CALIB_DIST, led_ry); -#endif - } - - prepare_data(&ts, buf); -} diff --git a/rpcs3/Emu/Io/TopShotElite.h b/rpcs3/Emu/Io/TopShotElite.h deleted file mode 100644 index 00e2752714..0000000000 --- a/rpcs3/Emu/Io/TopShotElite.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_topshotelite : public usb_device_emulated -{ -public: - usb_device_topshotelite(u32 controller_index, const std::array& location); - ~usb_device_topshotelite(); - - 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; - -private: - u32 m_controller_index; - u8 m_mode; -}; diff --git a/rpcs3/Emu/Io/TopShotFearmaster.cpp b/rpcs3/Emu/Io/TopShotFearmaster.cpp deleted file mode 100644 index d2c3e0962f..0000000000 --- a/rpcs3/Emu/Io/TopShotFearmaster.cpp +++ /dev/null @@ -1,423 +0,0 @@ -#include "stdafx.h" -#include "TopShotFearmaster.h" -#include "MouseHandler.h" -#include "Emu/IdManager.h" -#include "Emu/Io/topshotfearmaster_config.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/system_config.h" -#include "Input/pad_thread.h" - -LOG_CHANNEL(topshotfearmaster_log); - -#define TSF_CALIB_LOG false -// 0 < Calib_Top < Calib_Bottom < 0x2ff -// 0 < Calib_Right < Calib_Left < 0x3ff -constexpr u16 TSF_CALIB_TOP = 20; -constexpr u16 TSF_CALIB_BOTTOM = 840; -constexpr u16 TSF_CALIB_LEFT = 900; -constexpr u16 TSF_CALIB_RIGHT = 120; -constexpr u16 TSF_CALIB_DIST = 95; - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](topshotfearmaster_btn value) - { - switch (value) - { - case topshotfearmaster_btn::trigger: return "Trigger"; - case topshotfearmaster_btn::heartrate: return "Heartrate"; - case topshotfearmaster_btn::square: return "Square"; - case topshotfearmaster_btn::cross: return "Cross"; - case topshotfearmaster_btn::circle: return "Circle"; - case topshotfearmaster_btn::triangle: return "Triangle"; - case topshotfearmaster_btn::select: return "Select"; - case topshotfearmaster_btn::start: return "Start"; - case topshotfearmaster_btn::l3: return "L3"; - case topshotfearmaster_btn::ps: return "PS"; - case topshotfearmaster_btn::dpad_up: return "D-Pad Up"; - case topshotfearmaster_btn::dpad_down: return "D-Pad Down"; - case topshotfearmaster_btn::dpad_left: return "D-Pad Left"; - case topshotfearmaster_btn::dpad_right: return "D-Pad Right"; - case topshotfearmaster_btn::ls_x: return "Left Stick X-Axis"; - case topshotfearmaster_btn::ls_y: return "Left Stick Y-Axis"; - case topshotfearmaster_btn::count: return "Count"; - } - - return unknown; - }); -} - -#pragma pack(push, 1) -struct TopShotFearmaster_data -{ - uint8_t btn_square : 1; - uint8_t btn_cross : 1; - uint8_t btn_circle : 1; - uint8_t btn_triangle : 1; - uint8_t : 1; - uint8_t btn_trigger : 1; - uint8_t : 2; - - uint8_t btn_select : 1; - uint8_t btn_start : 1; - uint8_t btn_l3 : 1; - uint8_t btn_heartrate : 1; - uint8_t btn_ps : 1; - uint8_t : 3; - - uint8_t dpad; - uint8_t stick_lx; - uint8_t stick_ly; - union - { - struct - { - uint8_t stick_rx; - uint8_t stick_ry; - }; - uint16_t heartrate; - }; - - uint8_t led_lx_hi : 8; - uint8_t led_ly_hi : 6; - uint8_t led_lx_lo : 2; - uint8_t detect_l : 4; - uint8_t led_ly_lo : 4; - - uint8_t led_rx_hi : 8; - uint8_t led_ry_hi : 6; - uint8_t led_rx_lo : 2; - uint8_t detect_r : 4; - uint8_t led_ry_lo : 4; - - uint8_t : 8; - uint8_t : 8; - uint8_t : 8; - - uint8_t trigger; - uint8_t : 8; - uint8_t : 8; - uint16_t unk[4]; -}; -#pragma pack(pop) - -enum -{ - Dpad_North, - Dpad_NE, - Dpad_East, - Dpad_SE, - Dpad_South, - Dpad_SW, - Dpad_West, - Dpad_NW, - Dpad_None = 0x0f -}; - -usb_device_topshotfearmaster::usb_device_topshotfearmaster(u32 controller_index, const std::array& location) - : usb_device_emulated(location), m_controller_index(controller_index), m_mode(0) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0100, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x20, - .idVendor = 0x12ba, - .idProduct = 0x04a1, - .bcdDevice = 0x0108, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - .bNumConfigurations = 0x01}); - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 0x0029, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0x80, - .bMaxPower = 0x32})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x02, - .bInterfaceClass = 0x03, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, - .iInterface = 0x00})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, - UsbDeviceHID{ - .bcdHID = 0x0110, - .bCountryCode = 0x00, - .bNumDescriptors = 0x01, - .bDescriptorType = 0x22, - .wDescriptorLength = 0x0089})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x81, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0040, - .bInterval = 0x0a})); - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x02, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0040, - .bInterval = 0x0a})); - - add_string("Dangerous Hunts for Playstation (R) 3"); - add_string("Dangerous Hunts for Playstation (R) 3"); -} - -usb_device_topshotfearmaster::~usb_device_topshotfearmaster() -{ -} - -void usb_device_topshotfearmaster::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 100; - - switch (bmRequestType) - { - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE: // 0x21 - switch (bRequest) - { - case 0x09: // SET_REPORT - ensure(buf_size >= 8); - switch (buf[0]) - { - case 0x01: - topshotfearmaster_log.trace("Leds: %s/%s/%s/%s", - buf[2] & 1 ? "ON" : "OFF", - buf[2] & 2 ? "ON" : "OFF", - buf[2] & 4 ? "ON" : "OFF", - buf[2] & 8 ? "ON" : "OFF"); - break; - case 0x82: - m_mode = buf[2]; - break; - default: - topshotfearmaster_log.error("Unhandled SET_REPORT packet : %x", buf[0]); - break; - } - break; - default: - topshotfearmaster_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest); - break; - } - break; - default: - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - break; - } -} - -extern bool is_input_allowed(); - -static int get_heartrate_sensor_value(u8 heartrate) -{ - static const uint16_t sensor_data[] = { - 0x7af, 0x771, 0x737, 0x6ff, 0x6cb, 0x69a, 0x66c, 0x640, 0x616, 0x5ef, // 30-39 - 0x5ca, 0x5a6, 0x584, 0x563, 0x544, 0x527, 0x50a, 0x4ef, 0x4d5, 0x4bc, // 40-49 - 0x4a4, 0x48d, 0x477, 0x462, 0x44d, 0x439, 0x426, 0x413, 0x401, 0x3f0, // 50-59 - 0x3e0, 0x3cf, 0x3c0, 0x3b1, 0x3a2, 0x394, 0x386, 0x379, 0x36c, 0x35f, // 60-69 - 0x353, 0x347, 0x33b, 0x330, 0x325, 0x31b, 0x310, 0x306, 0x2fc, 0x2f3, // 70-79 - 0x2e9, 0x2e0, 0x2d7, 0x2ce, 0x2c6, 0x2bd, 0x2b5, 0x2ad, 0x2a6, 0x29e, // 80-89 - 0x297, 0x290, 0x289, 0x282, 0x27b, 0x274, 0x26e, 0x267, 0x261, 0x25b, // 90-99 - 0x255, 0x24f, 0x249, 0x243, 0x23e, 0x239, 0x233, 0x22e, 0x229, 0x224, // 100-109 - 0x21f, 0x21a, 0x215, 0x210, 0x20c, 0x207, 0x203, 0x1fe, 0x1fa, 0x1f6, // 110-119 - 0x1f2, 0x1ed, 0x1e9, 0x1e5, 0x1e2, 0x1de, 0x1da, 0x1d6, 0x1d3, 0x1cf, // 120-129 - 0x1cc, 0x1c8, 0x1c5, 0x1c1, 0x1be, 0x1bb, 0x1b7, 0x1b4, 0x1b1, 0x1ae // 130-139 - }; - - if (heartrate < 30 || heartrate > 139) - { - return 0; - } - - return sensor_data[heartrate - 30]; -} - -static void set_sensor_pos(struct TopShotFearmaster_data* ts, s32 led_lx, s32 led_ly, s32 led_rx, s32 led_ry, s32 detect_l, s32 detect_r) -{ - ts->led_lx_hi = led_lx >> 2; - ts->led_lx_lo = led_lx & 0x3; - ts->led_ly_hi = led_ly >> 4; - ts->led_ly_lo = led_ly & 0xf; - - ts->led_rx_hi = led_rx >> 2; - ts->led_rx_lo = led_rx & 0x3; - ts->led_ry_hi = led_ry >> 4; - ts->led_ry_lo = led_ry & 0xf; - - ts->detect_l = detect_l; - ts->detect_r = detect_r; -} - -static void prepare_data(const TopShotFearmaster_data* ts, u8* data) -{ - std::memcpy(data, ts, sizeof(TopShotFearmaster_data)); - topshotfearmaster_log.trace("interrupt_transfer: %s", fmt::buf_to_hexstring(data, sizeof(TopShotFearmaster_data))); -} - -void usb_device_topshotfearmaster::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer) -{ - ensure(buf_size >= sizeof(TopShotFearmaster_data)); - - transfer->fake = true; - transfer->expected_count = sizeof(TopShotFearmaster_data); - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 4000; - - struct TopShotFearmaster_data ts{}; - ts.dpad = Dpad_None; - ts.stick_lx = ts.stick_ly = ts.stick_rx = ts.stick_ry = 0x7f; - if (m_mode) - { - set_sensor_pos(&ts, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0xf, 0xf); - } - ts.unk[0] = ts.unk[1] = ts.unk[2] = ts.unk[3] = 0x0200; - - if (!is_input_allowed()) - { - prepare_data(&ts, buf); - return; - } - - if (g_cfg.io.mouse == mouse_handler::null) - { - topshotfearmaster_log.warning("Top Shot Fearmaster requires a Mouse Handler enabled"); - prepare_data(&ts, buf); - return; - } - - if (m_controller_index >= g_cfg_topshotfearmaster.players.size()) - { - topshotfearmaster_log.warning("Top Shot Fearmaster controllers are only supported for Player1 to Player%d", g_cfg_topshotfearmaster.players.size()); - prepare_data(&ts, buf); - return; - } - - bool up = false, right = false, down = false, left = false; - const auto input_callback = [&ts, &up, &down, &left, &right](topshotfearmaster_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; - - switch (btn) - { - case topshotfearmaster_btn::trigger: ts.btn_trigger |= 1; break; - case topshotfearmaster_btn::heartrate: ts.btn_heartrate |= 1; break; - case topshotfearmaster_btn::square: ts.btn_square |= 1; break; - case topshotfearmaster_btn::cross: ts.btn_cross |= 1; break; - case topshotfearmaster_btn::circle: ts.btn_circle |= 1; break; - case topshotfearmaster_btn::triangle: ts.btn_triangle |= 1; break; - case topshotfearmaster_btn::select: ts.btn_select |= 1; break; - case topshotfearmaster_btn::start: ts.btn_start |= 1; break; - case topshotfearmaster_btn::l3: ts.btn_l3 |= 1; break; - case topshotfearmaster_btn::ps: ts.btn_ps |= 1; break; - case topshotfearmaster_btn::dpad_up: up = true; break; - case topshotfearmaster_btn::dpad_down: down = true; break; - case topshotfearmaster_btn::dpad_left: left = true; break; - case topshotfearmaster_btn::dpad_right: right = true; break; - case topshotfearmaster_btn::ls_x: ts.stick_lx = static_cast(value); break; - case topshotfearmaster_btn::ls_y: ts.stick_ly = static_cast(value); break; - case topshotfearmaster_btn::count: break; - } - }; - - const auto& cfg = ::at32(g_cfg_topshotfearmaster.players, m_controller_index); - - { - std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_pad_thread(); - const auto& pads = gamepad_handler->GetPads(); - const auto& pad = ::at32(pads, m_controller_index); - if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) - { - cfg->handle_input(pad, true, input_callback); - } - } - - if (!up && !right && !down && !left) - ts.dpad = Dpad_None; - else if (up && !left && !right) - ts.dpad = Dpad_North; - else if (up && right) - ts.dpad = Dpad_NE; - else if (right && !up && !down) - ts.dpad = Dpad_East; - else if (down && right) - ts.dpad = Dpad_SE; - else if (down && !left && !right) - ts.dpad = Dpad_South; - else if (down && left) - ts.dpad = Dpad_SW; - else if (left && !up && !down) - ts.dpad = Dpad_West; - else if (up && left) - ts.dpad = Dpad_NW; - - if (m_mode) - { - auto& mouse_handler = g_fxo->get(); - std::lock_guard mouse_lock(mouse_handler.mutex); - - mouse_handler.Init(4); - - const u32 mouse_index = g_cfg.io.mouse == mouse_handler::basic ? 0 : m_controller_index; - if (mouse_index >= mouse_handler.GetMice().size()) - { - prepare_data(&ts, buf); - return; - } - - const Mouse& mouse_data = ::at32(mouse_handler.GetMice(), mouse_index); - cfg->handle_input(mouse_data, input_callback); - ts.trigger = ts.btn_trigger ? 0xff : 0x00; - ts.heartrate = ts.btn_heartrate ? get_heartrate_sensor_value(60) : 0; - - if (mouse_data.x_max <= 0 || mouse_data.y_max <= 0) - { - prepare_data(&ts, buf); - return; - } - - s32 led_lx = 0x3ff - (TSF_CALIB_RIGHT + (mouse_data.x_pos * (TSF_CALIB_LEFT - TSF_CALIB_RIGHT) / mouse_data.x_max) + TSF_CALIB_DIST); - s32 led_rx = 0x3ff - (TSF_CALIB_RIGHT + (mouse_data.x_pos * (TSF_CALIB_LEFT - TSF_CALIB_RIGHT) / mouse_data.x_max) - TSF_CALIB_DIST); - - s32 led_ly = TSF_CALIB_TOP + (mouse_data.y_pos * (TSF_CALIB_BOTTOM - TSF_CALIB_TOP) / mouse_data.y_max); - s32 led_ry = TSF_CALIB_TOP + (mouse_data.y_pos * (TSF_CALIB_BOTTOM - TSF_CALIB_TOP) / mouse_data.y_max); - - u8 detect_l = 0x2, detect_r = 0x2; // 0x2 = led detected / 0xf = undetected - - if (led_lx < 0 || led_lx > 0x3ff || led_ly < 0 || led_ly > 0x3ff) - { - led_lx = 0x3ff; - led_ly = 0x3ff; - detect_l = 0xf; - } - - if (led_rx < 0 || led_rx > 0x3ff || led_ry < 0 || led_ry > 0x3ff) - { - led_rx = 0x3ff; - led_ry = 0x3ff; - detect_r = 0xf; - } - - set_sensor_pos(&ts, led_lx, led_ly, led_rx, led_ry, detect_l, detect_r); - -#if TSF_CALIB_LOG - topshotfearmaster_log.error("L: %d x %d, R: %d x %d", led_lx + TSF_CALIB_DIST, led_ly, led_rx - TSF_CALIB_DIST, led_ry); -#endif - } - - prepare_data(&ts, buf); -} diff --git a/rpcs3/Emu/Io/TopShotFearmaster.h b/rpcs3/Emu/Io/TopShotFearmaster.h deleted file mode 100644 index dee955cd75..0000000000 --- a/rpcs3/Emu/Io/TopShotFearmaster.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_topshotfearmaster : public usb_device_emulated -{ -public: - usb_device_topshotfearmaster(u32 controller_index, const std::array& location); - ~usb_device_topshotfearmaster(); - - 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; - -private: - u32 m_controller_index; - u8 m_mode; -}; diff --git a/rpcs3/Emu/Io/Turntable.cpp b/rpcs3/Emu/Io/Turntable.cpp deleted file mode 100644 index b85666ea22..0000000000 --- a/rpcs3/Emu/Io/Turntable.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// DJ Hero Turntable controller emulator - -#include "stdafx.h" -#include "Turntable.h" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/Io/turntable_config.h" -#include "Input/pad_thread.h" -#include "Emu/system_config.h" - -LOG_CHANNEL(turntable_log, "TURN"); - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](turntable_btn value) - { - switch (value) - { - case turntable_btn::blue: return "Blue"; - case turntable_btn::green: return "Green"; - case turntable_btn::red: return "Red"; - case turntable_btn::dpad_up: return "D-Pad Up"; - case turntable_btn::dpad_down: return "D-Pad Down"; - case turntable_btn::dpad_left: return "D-Pad Left"; - case turntable_btn::dpad_right: return "D-Pad Right"; - case turntable_btn::start: return "Start"; - case turntable_btn::select: return "Select"; - case turntable_btn::square: return "Square"; - case turntable_btn::circle: return "Circle"; - case turntable_btn::cross: return "Cross"; - case turntable_btn::triangle: return "Triangle"; - case turntable_btn::right_turntable: return "Right Turntable"; - case turntable_btn::crossfader: return "Crossfader"; - case turntable_btn::effects_dial: return "Effects Dial"; - case turntable_btn::count: return "Count"; - } - - return unknown; - }); -} - -usb_device_turntable::usb_device_turntable(u32 controller_index, const std::array& location) - : usb_device_emulated(location), m_controller_index(controller_index) -{ - 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() -{ -} - -std::shared_ptr usb_device_turntable::make_instance(u32 controller_index, const std::array& location) -{ - return std::make_shared(controller_index, location); -} - -u16 usb_device_turntable::get_num_emu_devices() -{ - return static_cast(g_cfg.io.turntable.get()); -} - -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: buf_size=0x%02X, Type=0x%02X, bRequest=0x%02X, bmRequestType=0x%02X", buf_size, (buf_size > 0) ? buf[0] : -1, bRequest, bmRequestType); - 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) -{ - ensure(buf_size >= 27); - - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - // Turntable runs at 100hz --> 10ms - // But make the emulated table go at 1ms for better input behavior - transfer->expected_time = get_timestamp() + 1'000; - - 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 - - std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_pad_thread(); - const auto& pads = handler->GetPads(); - const auto& pad = ::at32(pads, m_controller_index); - - if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) - return; - - const auto& cfg = ::at32(g_cfg_turntable.players, m_controller_index); - cfg->handle_input(pad, true, [&buf](turntable_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; - - switch (btn) - { - case turntable_btn::blue: - buf[0] |= 0x01; // Square Button - buf[7] = ~buf[7]; // Square Button - buf[23] |= 0x04; // Right Platter Blue - break; - case turntable_btn::green: - buf[0] |= 0x02; // Cross Button - buf[9] = ~buf[9]; // Cross Button - buf[23] |= 0x01; // Right Platter Green - break; - case turntable_btn::red: - buf[0] |= 0x04; // Circle Button - buf[12] = ~buf[12]; // Circle Button - buf[23] |= 0x02; // Right Platter Red - break; - case turntable_btn::triangle: - buf[0] |= 0x08; // Triangle Button / Euphoria - buf[11] = ~buf[11]; // Triangle Button / Euphoria - break; - case turntable_btn::cross: - buf[0] |= 0x02; // Cross Button Only - buf[9] = ~buf[9]; // Cross Button Only - break; - case turntable_btn::circle: - buf[0] |= 0x04; // Circle Button Only - buf[12] = ~buf[12]; // Circle Button Only - break; - case turntable_btn::square: - buf[0] |= 0x01; // Square Button Only - buf[7] = ~buf[7]; // Square Button Only - break; - case turntable_btn::dpad_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 turntable_btn::dpad_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 turntable_btn::dpad_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 turntable_btn::dpad_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 turntable_btn::start: - buf[1] |= 0x02; // Start - break; - case turntable_btn::select: - buf[1] |= 0x01; // Select - break; - case turntable_btn::right_turntable: - // DJ Hero does not register input if the turntable is 0, so force it to 1. - buf[6] = std::max(1, 255 - value); // Right Turntable - // DJ Hero requires turntables to be centered at 128. - // If this axis ends up centered at 127, force it to 128. - if (buf[6] == 127) - { - buf[6] = 128; - } - break; - case turntable_btn::crossfader: - buf[21] = ((255 - value) & 0x3F) << 2; // Crossfader, lower 6 bits - buf[22] = ((255 - value) & 0xC0) >> 6; // Crossfader, upper 2 bits - break; - case turntable_btn::effects_dial: - buf[19] = (value & 0x3F) << 2; // Effects Dial, lower 6 bits - buf[20] = (value & 0xC0) >> 6; // Effects Dial, upper 2 bits - break; - case turntable_btn::count: - break; - } - }); -} diff --git a/rpcs3/Emu/Io/Turntable.h b/rpcs3/Emu/Io/Turntable.h deleted file mode 100644 index f8186e9098..0000000000 --- a/rpcs3/Emu/Io/Turntable.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" - -class usb_device_turntable : public usb_device_emulated -{ -public: - usb_device_turntable(u32 controller_index, const std::array& location); - ~usb_device_turntable(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - -private: - u32 m_controller_index; -}; diff --git a/rpcs3/Emu/Io/buzz_config.h b/rpcs3/Emu/Io/buzz_config.h deleted file mode 100644 index 3012a7b99a..0000000000 --- a/rpcs3/Emu/Io/buzz_config.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class buzz_btn -{ - red, - yellow, - green, - orange, - blue, - - count -}; - -struct cfg_buzzer final : public emulated_pad_config -{ - cfg_buzzer(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn red{this, "Red", buzz_btn::red, pad_button::R1}; - cfg_pad_btn yellow{this, "Yellow", buzz_btn::yellow, pad_button::cross}; - cfg_pad_btn green{this, "Green", buzz_btn::green, pad_button::circle}; - cfg_pad_btn orange{this, "Orange", buzz_btn::orange, pad_button::square}; - cfg_pad_btn blue{this, "Blue", buzz_btn::blue, pad_button::triangle}; -}; - -struct cfg_buzz final : public emulated_pads_config -{ - cfg_buzz() : emulated_pads_config("buzz") {}; -}; - -extern cfg_buzz g_cfg_buzz; diff --git a/rpcs3/Emu/Io/ghltar_config.h b/rpcs3/Emu/Io/ghltar_config.h deleted file mode 100644 index 302eda75e3..0000000000 --- a/rpcs3/Emu/Io/ghltar_config.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class ghltar_btn -{ - w1, - w2, - w3, - b1, - b2, - b3, - start, - hero_power, - ghtv, - strum_down, - strum_up, - dpad_left, - dpad_right, - whammy, - tilt, - - count -}; - -struct cfg_ghltar final : public emulated_pad_config -{ - cfg_ghltar(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn w1{this, "W1", ghltar_btn::w1, pad_button::square}; - cfg_pad_btn w2{this, "W2", ghltar_btn::w2, pad_button::L1}; - cfg_pad_btn w3{this, "W3", ghltar_btn::w3, pad_button::R1}; - cfg_pad_btn b1{this, "B1", ghltar_btn::b1, pad_button::cross}; - cfg_pad_btn b2{this, "B2", ghltar_btn::b2, pad_button::circle}; - cfg_pad_btn b3{this, "B3", ghltar_btn::b3, pad_button::triangle}; - cfg_pad_btn start{this, "Start", ghltar_btn::start, pad_button::start}; - cfg_pad_btn hero_power{this, "Hero Power", ghltar_btn::hero_power, pad_button::select}; - cfg_pad_btn ghtv{this, "GHTV", ghltar_btn::ghtv, pad_button::L3}; - cfg_pad_btn strum_down{this, "Strum Down", ghltar_btn::strum_down, pad_button::dpad_down}; - cfg_pad_btn strum_up{this, "Strum Up", ghltar_btn::strum_up, pad_button::dpad_up}; - cfg_pad_btn dpad_left{this, "D-Pad Left", ghltar_btn::dpad_left, pad_button::dpad_left}; - cfg_pad_btn dpad_right{this, "D-Pad Right", ghltar_btn::dpad_right, pad_button::dpad_right}; - cfg_pad_btn whammy{this, "Whammy", ghltar_btn::whammy, pad_button::rs_y}; - cfg_pad_btn tilt{this, "tilt", ghltar_btn::tilt, pad_button::rs_x}; -}; - -struct cfg_ghltars final : public emulated_pads_config -{ - cfg_ghltars() : emulated_pads_config("ghltar") {}; -}; - -extern cfg_ghltars g_cfg_ghltar; diff --git a/rpcs3/Emu/Io/guncon3_config.h b/rpcs3/Emu/Io/guncon3_config.h deleted file mode 100644 index c2ea82a9f3..0000000000 --- a/rpcs3/Emu/Io/guncon3_config.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class guncon3_btn -{ - trigger, - a1, - a2, - a3, - b1, - b2, - b3, - c1, - c2, - as_x, - as_y, - bs_x, - bs_y, - - count -}; - -struct cfg_gc3 final : public emulated_pad_config -{ - cfg_gc3(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn trigger{this, "Trigger", guncon3_btn::trigger, pad_button::cross}; - cfg_pad_btn a1{this, "A1", guncon3_btn::a1, pad_button::L1}; - cfg_pad_btn a2{this, "A2", guncon3_btn::a2, pad_button::L2}; - cfg_pad_btn a3{this, "A3", guncon3_btn::a3, pad_button::L3}; - cfg_pad_btn b1{this, "B1", guncon3_btn::b1, pad_button::R1}; - cfg_pad_btn b2{this, "B2", guncon3_btn::b2, pad_button::R2}; - cfg_pad_btn b3{this, "B3", guncon3_btn::b3, pad_button::R3}; - cfg_pad_btn c1{this, "C1", guncon3_btn::c1, pad_button::select}; - cfg_pad_btn c2{this, "C2", guncon3_btn::c2, pad_button::start}; - cfg_pad_btn as_x{this, "A-stick X-Axis", guncon3_btn::as_x, pad_button::ls_x}; - cfg_pad_btn as_y{this, "A-stick Y-Axis", guncon3_btn::as_y, pad_button::ls_y}; - cfg_pad_btn bs_x{this, "B-stick X-Axis", guncon3_btn::bs_x, pad_button::rs_x}; - cfg_pad_btn bs_y{this, "B-stick Y-Axis", guncon3_btn::bs_y, pad_button::rs_y}; -}; - -struct cfg_guncon3 final : public emulated_pads_config -{ - cfg_guncon3() : emulated_pads_config("guncon3") {}; -}; - -extern cfg_guncon3 g_cfg_guncon3; diff --git a/rpcs3/Emu/Io/midi_config_types.cpp b/rpcs3/Emu/Io/midi_config_types.cpp deleted file mode 100644 index cc7520cccc..0000000000 --- a/rpcs3/Emu/Io/midi_config_types.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "stdafx.h" -#include "midi_config_types.h" -#include "util/StrUtil.h" -#include "util/Config.h" - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](midi_device_type value) - { - switch (value) - { - case midi_device_type::guitar: return "Guitar (17 frets)"; - case midi_device_type::guitar_22fret: return "Guitar (22 frets)"; - case midi_device_type::keyboard: return "Keyboard"; - case midi_device_type::drums: return "Drums"; - } - - return unknown; - }); -} - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - const midi_device& obj = get_object(arg); - fmt::append(out, "%sßßß%s", obj.type, obj.name); -} - -midi_device midi_device::from_string(const std::string& str) -{ - midi_device res{}; - - if (const std::vector parts = fmt::split(str, {"ßßß"}); !parts.empty()) - { - u64 result; - - if (cfg::try_to_enum_value(&result, &fmt_class_string::format, ::at32(parts, 0))) - { - res.type = static_cast(static_cast>(result)); - } - - if (parts.size() == 2) - { - res.name = ::at32(parts, 1); - } - } - - return res; -} diff --git a/rpcs3/Emu/Io/midi_config_types.h b/rpcs3/Emu/Io/midi_config_types.h deleted file mode 100644 index 9d2f40adf1..0000000000 --- a/rpcs3/Emu/Io/midi_config_types.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -static constexpr usz max_midi_devices = 3; - -enum class midi_device_type -{ - keyboard, - guitar, - guitar_22fret, - drums, -}; - -struct midi_device -{ - midi_device_type type{}; - std::string name; - - static midi_device from_string(const std::string& str); -}; diff --git a/rpcs3/Emu/Io/rb3drums_config.cpp b/rpcs3/Emu/Io/rb3drums_config.cpp deleted file mode 100644 index c827333813..0000000000 --- a/rpcs3/Emu/Io/rb3drums_config.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "stdafx.h" -#include "rb3drums_config.h" - -LOG_CHANNEL(cfg_log, "CFG"); - -cfg_rb3drums g_cfg_rb3drums; - -cfg_rb3drums::cfg_rb3drums() - : cfg::node(), path(fs::get_config_dir(true) + "rb3drums.yml") -{ -} - -bool cfg_rb3drums::load() -{ - cfg_log.notice("Loading rb3drums config from '%s'", path); - - if (fs::file cfg_file{path, fs::read}) - { - return from_string(cfg_file.to_string()); - } - - cfg_log.notice("No rb3drums config found. Using default settings. Path: %s", path); - from_default(); - save(); - return false; -} - -void cfg_rb3drums::save() -{ - cfg_log.notice("Saving rb3drums config to '%s'", path); - - if (!cfg::node::save(path)) - { - cfg_log.error("Failed to save rb3drums config to '%s' (error=%s)", path, fs::g_tls_error); - } - - reload_requested = true; -} diff --git a/rpcs3/Emu/Io/rb3drums_config.h b/rpcs3/Emu/Io/rb3drums_config.h deleted file mode 100644 index 3670d75134..0000000000 --- a/rpcs3/Emu/Io/rb3drums_config.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "util/Config.h" - -struct cfg_rb3drums final : cfg::node -{ - cfg_rb3drums(); - bool load(); - void save(); - - cfg::uint<1, 100> pulse_ms{this, "Pulse width ms", 30, true}; - cfg::uint<1, 127> minimum_velocity{this, "Minimum velocity", 10, true}; - cfg::uint<1, 5000> combo_window_ms{this, "Combo window in milliseconds", 2000, true}; - cfg::_bool stagger_cymbals{this, "Stagger cymbal hits", true, true}; - cfg::string midi_overrides{this, "Midi id to note override", "", true}; - cfg::string combo_start{this, "Combo Start", "HihatPedal,HihatPedal,HihatPedal,Snare", true}; - cfg::string combo_select{this, "Combo Select", "HihatPedal,HihatPedal,HihatPedal,SnareRim", true}; - cfg::string combo_toggle_hold_kick{this, "Combo Toggle Hold Kick", "HihatPedal,HihatPedal,HihatPedal,Kick", true}; - cfg::uint<0, 255> midi_cc_status{this, "Midi CC status", 0xB0, true}; - cfg::uint<0, 127> midi_cc_number{this, "Midi CC control number", 4, true}; - cfg::uint<0, 127> midi_cc_threshold{this, "Midi CC threshold", 64, true}; - cfg::_bool midi_cc_invert_threshold{this, "Midi CC invert threshold", false, true}; - - const std::string path; - - atomic_t reload_requested = false; -}; - -extern cfg_rb3drums g_cfg_rb3drums; diff --git a/rpcs3/Emu/Io/topshotelite_config.h b/rpcs3/Emu/Io/topshotelite_config.h deleted file mode 100644 index fa9ca952d2..0000000000 --- a/rpcs3/Emu/Io/topshotelite_config.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class topshotelite_btn -{ - trigger, - reload, - square, - cross, - circle, - triangle, - select, - start, - l3, - r3, - ps, - dpad_up, - dpad_down, - dpad_left, - dpad_right, - ls_x, - ls_y, - rs_x, - rs_y, - - count -}; - -struct cfg_tse final : public emulated_pad_config -{ - cfg_tse(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn trigger{this, "Trigger", topshotelite_btn::trigger, pad_button::mouse_button_1}; - cfg_pad_btn reload{this, "Reload", topshotelite_btn::reload, pad_button::mouse_button_2}; - cfg_pad_btn square{this, "Square", topshotelite_btn::square, pad_button::square}; - cfg_pad_btn cross{this, "Cross", topshotelite_btn::cross, pad_button::cross}; - cfg_pad_btn circle{this, "Circle", topshotelite_btn::circle, pad_button::circle}; - cfg_pad_btn triangle{this, "Triangle", topshotelite_btn::triangle, pad_button::triangle}; - cfg_pad_btn select{this, "Select", topshotelite_btn::select, pad_button::select}; - cfg_pad_btn start{this, "Start", topshotelite_btn::start, pad_button::start}; - cfg_pad_btn l3{this, "L3", topshotelite_btn::l3, pad_button::L3}; - cfg_pad_btn r3{this, "R3", topshotelite_btn::r3, pad_button::R3}; - cfg_pad_btn ps{this, "PS", topshotelite_btn::ps, pad_button::ps}; - cfg_pad_btn dpad_up{this, "D-Pad Up", topshotelite_btn::dpad_up, pad_button::dpad_up}; - cfg_pad_btn dpad_down{this, "D-Pad Down", topshotelite_btn::dpad_down, pad_button::dpad_down}; - cfg_pad_btn dpad_left{this, "D-Pad Left", topshotelite_btn::dpad_left, pad_button::dpad_left}; - cfg_pad_btn dpad_right{this, "D-Pad Right", topshotelite_btn::dpad_right, pad_button::dpad_right}; - cfg_pad_btn ls_x{this, "Left Stick X-Axis", topshotelite_btn::ls_x, pad_button::ls_x}; - cfg_pad_btn ls_y{this, "Left Stick Y-Axis", topshotelite_btn::ls_y, pad_button::ls_y}; - cfg_pad_btn rs_x{this, "Right Stick X-Axis", topshotelite_btn::rs_x, pad_button::rs_x}; - cfg_pad_btn rs_y{this, "Right Stick Y-Axis", topshotelite_btn::rs_y, pad_button::rs_y}; -}; - -struct cfg_topshotelite final : public emulated_pads_config -{ - cfg_topshotelite() : emulated_pads_config("topshotelite") {}; -}; - -extern cfg_topshotelite g_cfg_topshotelite; diff --git a/rpcs3/Emu/Io/topshotfearmaster_config.h b/rpcs3/Emu/Io/topshotfearmaster_config.h deleted file mode 100644 index cd2aadf02d..0000000000 --- a/rpcs3/Emu/Io/topshotfearmaster_config.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class topshotfearmaster_btn -{ - trigger, - heartrate, - square, - cross, - circle, - triangle, - select, - start, - l3, - ps, - dpad_up, - dpad_down, - dpad_left, - dpad_right, - ls_x, - ls_y, - - count -}; - -struct cfg_tsf final : public emulated_pad_config -{ - cfg_tsf(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn trigger{this, "Trigger", topshotfearmaster_btn::trigger, pad_button::mouse_button_1}; - cfg_pad_btn heartrate{this, "Heartrate", topshotfearmaster_btn::heartrate, pad_button::mouse_button_2}; - cfg_pad_btn square{this, "Square", topshotfearmaster_btn::square, pad_button::square}; - cfg_pad_btn cross{this, "Cross", topshotfearmaster_btn::cross, pad_button::cross}; - cfg_pad_btn circle{this, "Circle", topshotfearmaster_btn::circle, pad_button::circle}; - cfg_pad_btn triangle{this, "Triangle", topshotfearmaster_btn::triangle, pad_button::triangle}; - cfg_pad_btn select{this, "Select", topshotfearmaster_btn::select, pad_button::select}; - cfg_pad_btn start{this, "Start", topshotfearmaster_btn::start, pad_button::start}; - cfg_pad_btn l3{this, "L3", topshotfearmaster_btn::l3, pad_button::L3}; - cfg_pad_btn ps{this, "PS", topshotfearmaster_btn::ps, pad_button::ps}; - cfg_pad_btn dpad_up{this, "D-Pad Up", topshotfearmaster_btn::dpad_up, pad_button::dpad_up}; - cfg_pad_btn dpad_down{this, "D-Pad Down", topshotfearmaster_btn::dpad_down, pad_button::dpad_down}; - cfg_pad_btn dpad_left{this, "D-Pad Left", topshotfearmaster_btn::dpad_left, pad_button::dpad_left}; - cfg_pad_btn dpad_right{this, "D-Pad Right", topshotfearmaster_btn::dpad_right, pad_button::dpad_right}; - cfg_pad_btn ls_x{this, "Left Stick X-Axis", topshotfearmaster_btn::ls_x, pad_button::ls_x}; - cfg_pad_btn ls_y{this, "Left Stick Y-Axis", topshotfearmaster_btn::ls_y, pad_button::ls_y}; -}; - -struct cfg_topshotfearmaster final : public emulated_pads_config -{ - cfg_topshotfearmaster() : emulated_pads_config("topshotfearmaster") {}; -}; - -extern cfg_topshotfearmaster g_cfg_topshotfearmaster; diff --git a/rpcs3/Emu/Io/turntable_config.h b/rpcs3/Emu/Io/turntable_config.h deleted file mode 100644 index b50a24fc82..0000000000 --- a/rpcs3/Emu/Io/turntable_config.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class turntable_btn -{ - red, - green, - blue, - dpad_up, - dpad_down, - dpad_left, - dpad_right, - start, - select, - square, - circle, - cross, - triangle, - right_turntable, - crossfader, - effects_dial, - - count -}; - -struct cfg_turntable final : public emulated_pad_config -{ - cfg_turntable(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn blue{this, "Blue", turntable_btn::blue, pad_button::square}; - cfg_pad_btn green{this, "Green", turntable_btn::green, pad_button::cross}; - cfg_pad_btn red{this, "Red", turntable_btn::red, pad_button::circle}; - cfg_pad_btn dpad_up{this, "D-Pad Up", turntable_btn::dpad_up, pad_button::dpad_up}; - cfg_pad_btn dpad_down{this, "D-Pad Down", turntable_btn::dpad_down, pad_button::dpad_down}; - cfg_pad_btn dpad_left{this, "D-Pad Left", turntable_btn::dpad_left, pad_button::dpad_left}; - cfg_pad_btn dpad_right{this, "D-Pad Right", turntable_btn::dpad_right, pad_button::dpad_right}; - cfg_pad_btn start{this, "Start", turntable_btn::start, pad_button::start}; - cfg_pad_btn select{this, "Select", turntable_btn::select, pad_button::select}; - cfg_pad_btn square{this, "Square", turntable_btn::square, pad_button::R2}; - cfg_pad_btn circle{this, "Circle", turntable_btn::circle, pad_button::L1}; - cfg_pad_btn cross{this, "Cross", turntable_btn::cross, pad_button::R1}; - cfg_pad_btn triangle{this, "Triangle", turntable_btn::triangle, pad_button::triangle}; - cfg_pad_btn right_turntable{this, "Right Turntable", turntable_btn::right_turntable, pad_button::ls_y}; - cfg_pad_btn crossfader{this, "Crossfader", turntable_btn::crossfader, pad_button::rs_y}; - cfg_pad_btn effects_dial{this, "Effects Dial", turntable_btn::effects_dial, pad_button::rs_x}; -}; - -struct cfg_turntables final : public emulated_pads_config -{ - cfg_turntables() : emulated_pads_config("turntable") {}; -}; - -extern cfg_turntables g_cfg_turntable; diff --git a/rpcs3/Emu/Io/usb_device.cpp b/rpcs3/Emu/Io/usb_device.cpp deleted file mode 100644 index 42c5174733..0000000000 --- a/rpcs3/Emu/Io/usb_device.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" -#include "Emu/Cell/timers.hpp" -#include "Emu/Cell/lv2/sys_usbd.h" -#include "Emu/Io/usb_device.h" -#include "util/StrUtil.h" -#include - -LOG_CHANNEL(sys_usbd); - -extern void LIBUSB_CALL callback_transfer(struct libusb_transfer* transfer); - -////////////////////////////////////////////////////////////////// -// ALL DEVICES /////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////// - -usb_device::usb_device(const std::array& location) -{ - this->location = location; -} - -void usb_device::get_location(u8* location) const -{ - memcpy(location, this->location.data(), 7); -} - -void usb_device::read_descriptors() -{ -} - -u32 usb_device::get_configuration(u8* buf) -{ - *buf = current_config; - return sizeof(u8); -} - -bool usb_device::set_configuration(u8 cfg_num) -{ - current_config = cfg_num; - return true; -} - -bool usb_device::set_interface(u8 int_num) -{ - current_interface = int_num; - return true; -} - -u64 usb_device::get_timestamp() -{ - return (get_system_time() - Emu.GetPauseTime()); -} - -////////////////////////////////////////////////////////////////// -// PASSTHROUGH DEVICE //////////////////////////////////////////// -////////////////////////////////////////////////////////////////// -usb_device_passthrough::usb_device_passthrough(libusb_device* _device, libusb_device_descriptor& desc, const std::array& location) - : usb_device(location), lusb_device(_device) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{desc.bcdUSB, desc.bDeviceClass, desc.bDeviceSubClass, desc.bDeviceProtocol, desc.bMaxPacketSize0, desc.idVendor, desc.idProduct, - desc.bcdDevice, desc.iManufacturer, desc.iProduct, desc.iSerialNumber, desc.bNumConfigurations}); -} - -usb_device_passthrough::~usb_device_passthrough() -{ - if (lusb_handle) - { - libusb_release_interface(lusb_handle, 0); - libusb_close(lusb_handle); - } - - if (lusb_device) - { - libusb_unref_device(lusb_device); - } -} - -void usb_device_passthrough::send_libusb_transfer(libusb_transfer* transfer) -{ - while (true) - { - auto res = libusb_submit_transfer(transfer); - switch (res) - { - case LIBUSB_SUCCESS: return; - case LIBUSB_ERROR_BUSY: continue; - default: - { - sys_usbd.error("Unexpected error from libusb_submit_transfer: %d(%s)", res, libusb_error_name(res)); - return; - } - } - } -} - -bool usb_device_passthrough::open_device() -{ - if (libusb_open(lusb_device, &lusb_handle) == LIBUSB_SUCCESS) - { -#ifdef __linux__ - libusb_set_auto_detach_kernel_driver(lusb_handle, true); -#endif - return true; - } - - return false; -} - -void usb_device_passthrough::read_descriptors() -{ - // Directly getting configuration descriptors from the device instead of going through libusb parsing functions as they're not needed - for (u8 index = 0; index < device._device.bNumConfigurations; index++) - { - u8 buf[1000]; - int ssize = libusb_control_transfer(lusb_handle, +LIBUSB_ENDPOINT_IN | +LIBUSB_REQUEST_TYPE_STANDARD | +LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, 0x0200 | index, 0, buf, 1000, 0); - if (ssize < 0) - { - sys_usbd.fatal("Couldn't get the config from the device: %d(%s)", ssize, libusb_error_name(ssize)); - continue; - } - - // Minimalistic parse - auto& conf = device.add_node(UsbDescriptorNode(buf[0], buf[1], &buf[2])); - - for (int index = buf[0]; index < ssize;) - { - conf.add_node(UsbDescriptorNode(buf[index], buf[index + 1], &buf[index + 2])); - index += buf[index]; - } - } -} - -u32 usb_device_passthrough::get_configuration(u8* buf) -{ - return (libusb_get_configuration(lusb_handle, reinterpret_cast(buf)) == LIBUSB_SUCCESS) ? sizeof(u8) : 0; -}; - -bool usb_device_passthrough::set_configuration(u8 cfg_num) -{ - usb_device::set_configuration(cfg_num); - return (libusb_set_configuration(lusb_handle, cfg_num) == LIBUSB_SUCCESS); -}; - -bool usb_device_passthrough::set_interface(u8 int_num) -{ - usb_device::set_interface(int_num); - return (libusb_claim_interface(lusb_handle, int_num) == LIBUSB_SUCCESS); -} - -void usb_device_passthrough::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, [[maybe_unused]] u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - if (transfer->setup_buf.size() < buf_size + LIBUSB_CONTROL_SETUP_SIZE) - transfer->setup_buf.resize(buf_size + LIBUSB_CONTROL_SETUP_SIZE); - - transfer->control_destbuf = (bmRequestType & LIBUSB_ENDPOINT_IN) ? buf : nullptr; - - libusb_fill_control_setup(transfer->setup_buf.data(), bmRequestType, bRequest, wValue, wIndex, buf_size); - memcpy(transfer->setup_buf.data() + LIBUSB_CONTROL_SETUP_SIZE, buf, buf_size); - libusb_fill_control_transfer(transfer->transfer, lusb_handle, transfer->setup_buf.data(), callback_transfer, transfer, 0); - send_libusb_transfer(transfer->transfer); -} - -void usb_device_passthrough::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) -{ - libusb_fill_interrupt_transfer(transfer->transfer, lusb_handle, endpoint, buf, buf_size, callback_transfer, transfer, 0); - send_libusb_transfer(transfer->transfer); -} - -void usb_device_passthrough::isochronous_transfer(UsbTransfer* transfer) -{ - // TODO actual endpoint - // TODO actual size? - libusb_fill_iso_transfer(transfer->transfer, lusb_handle, 0x81, static_cast(transfer->iso_request.buf.get_ptr()), 0xFFFF, transfer->iso_request.num_packets, callback_transfer, transfer, 0); - - for (u32 index = 0; index < transfer->iso_request.num_packets; index++) - { - transfer->transfer->iso_packet_desc[index].length = transfer->iso_request.packets[index]; - } - - send_libusb_transfer(transfer->transfer); -} - -////////////////////////////////////////////////////////////////// -// EMULATED DEVICE /////////////////////////////////////////////// -////////////////////////////////////////////////////////////////// -usb_device_emulated::usb_device_emulated(const std::array& location) - : usb_device(location) -{ -} - -usb_device_emulated::usb_device_emulated(const UsbDeviceDescriptor& _device, const std::array& location) - : usb_device(location) -{ - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, _device); -} - -bool usb_device_emulated::open_device() -{ - return true; -} - -u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size) -{ - if (!buf) - { - return 0; - } - - std::array header; - header = {static_cast(header.size()), type}; - - u32 expected_count = std::min(static_cast(header.size()), buf_size); - std::memcpy(buf, header.data(), expected_count); - - if (expected_count < header.size()) - return expected_count; - - switch (type) - { - case USB_DESCRIPTOR_DEVICE: - { - buf[0] = device.bLength; - expected_count = std::min(device.bLength, ::narrow(buf_size)); - std::memcpy(buf + header.size(), device.data, expected_count - header.size()); - break; - } - case USB_DESCRIPTOR_CONFIG: - { - if (index < device.subnodes.size()) - { - buf[0] = device.subnodes[index].bLength; - expected_count = std::min(device.subnodes[index].bLength, ::narrow(buf_size)); - std::memcpy(buf + header.size(), device.subnodes[index].data, expected_count - header.size()); - } - break; - } - case USB_DESCRIPTOR_STRING: - { - if (index < strings.size() + 1) - { - if (index == 0) - { - constexpr u8 len = static_cast(sizeof(u16) + header.size()); - buf[0] = len; - expected_count = std::min(len, ::narrow(buf_size)); - constexpr le_t langid = 0x0409; // English (United States) - std::memcpy(buf + header.size(), &langid, expected_count - header.size()); - } - else - { - const std::u16string u16str = utf8_to_utf16(strings[index - 1]); - const u8 len = static_cast(std::min(u16str.size() * sizeof(u16) + header.size(), static_cast(0xFF))); - buf[0] = len; - expected_count = std::min(len, ::narrow(std::min(255, buf_size))); - std::memcpy(buf + header.size(), u16str.data(), expected_count - header.size()); - } - } - break; - } - default: sys_usbd.error("Unhandled DescriptorType: get_descriptor(type=0x%02x, index=0x%02x, buf=*0x%x, buf_size=0x%x)", type, index, buf, buf_size); break; - } - - return expected_count; -} - -u32 usb_device_emulated::get_status(bool self_powered, bool remote_wakeup, u8* buf, u32 buf_size) -{ - const u32 expected_count = buf ? std::min(sizeof(u16), buf_size) : 0; - const u16 device_status = static_cast(self_powered) | static_cast(remote_wakeup) << 1; - std::memcpy(buf, &device_status, expected_count); - return expected_count; -} - -void usb_device_emulated::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 /*wLength*/, u32 buf_size, u8* buf, UsbTransfer* transfer) -{ - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = usb_device::get_timestamp() + 100; - - switch (bmRequestType) - { - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE: // 0x00 - switch (bRequest) - { - case LIBUSB_REQUEST_SET_CONFIGURATION: usb_device::set_configuration(::narrow(wValue)); break; - default: sys_usbd.error("Unhandled control transfer(0x%02x): 0x%02x", bmRequestType, bRequest); break; - } - break; - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_INTERFACE: // 0x01 - switch (bRequest) - { - case LIBUSB_REQUEST_SET_INTERFACE: usb_device::set_interface(::narrow(wIndex)); break; - default: sys_usbd.error("Unhandled control transfer(0x%02x): 0x%02x", bmRequestType, bRequest); break; - } - break; - case 0U /*silences warning*/ | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE: // 0x80 - switch (bRequest) - { - case LIBUSB_REQUEST_GET_STATUS: transfer->expected_count = get_status(false, false, buf, buf_size); break; - case LIBUSB_REQUEST_GET_DESCRIPTOR: transfer->expected_count = get_descriptor(wValue >> 8, wValue & 0xFF, buf, buf_size); break; - case LIBUSB_REQUEST_GET_CONFIGURATION: transfer->expected_count = get_configuration(buf); break; - default: sys_usbd.error("Unhandled control transfer(0x%02x): 0x%02x", bmRequestType, bRequest); break; - } - break; - default: sys_usbd.error("Unhandled control transfer: 0x%02x", bmRequestType); break; - } -} - -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -void usb_device_emulated::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) -{ -} - -void usb_device_emulated::isochronous_transfer(UsbTransfer* transfer) -{ -} - -void usb_device_emulated::add_string(std::string str) -{ - strings.emplace_back(std::move(str)); -} diff --git a/rpcs3/Emu/Io/usb_device.h b/rpcs3/Emu/Io/usb_device.h deleted file mode 100644 index d8884ffc8c..0000000000 --- a/rpcs3/Emu/Io/usb_device.h +++ /dev/null @@ -1,249 +0,0 @@ -#pragma once - -#ifdef _MSC_VER -#pragma warning(push, 0) -#else -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wall" -#pragma GCC diagnostic ignored "-Wextra" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#endif -#include -#ifdef _MSC_VER -#pragma warning(pop) -#else -#pragma GCC diagnostic pop -#endif - -#include "Emu/Cell/lv2/sys_usbd.h" - -struct UsbTransfer; - -// Usb descriptors -enum : u8 -{ - USB_DESCRIPTOR_DEVICE = 0x01, - USB_DESCRIPTOR_CONFIG = 0x02, - USB_DESCRIPTOR_STRING = 0x03, - USB_DESCRIPTOR_INTERFACE = 0x04, - USB_DESCRIPTOR_ENDPOINT = 0x05, - USB_DESCRIPTOR_HID = 0x21, - USB_DESCRIPTOR_ACI = 0x24, - USB_DESCRIPTOR_ENDPOINT_ASI = 0x25, -}; - -struct UsbDeviceDescriptor -{ - le_t bcdUSB; - u8 bDeviceClass; - u8 bDeviceSubClass; - u8 bDeviceProtocol; - u8 bMaxPacketSize0; - le_t idVendor; - le_t idProduct; - le_t bcdDevice; - u8 iManufacturer; - u8 iProduct; - u8 iSerialNumber; - u8 bNumConfigurations; -}; - -struct UsbDeviceConfiguration -{ - le_t wTotalLength; - u8 bNumInterfaces; - u8 bConfigurationValue; - u8 iConfiguration; - u8 bmAttributes; - u8 bMaxPower; -}; - -struct UsbDeviceInterface -{ - u8 bInterfaceNumber; - u8 bAlternateSetting; - u8 bNumEndpoints; - u8 bInterfaceClass; - u8 bInterfaceSubClass; - u8 bInterfaceProtocol; - u8 iInterface; -}; - -struct UsbDeviceEndpoint -{ - u8 bEndpointAddress; - u8 bmAttributes; - le_t wMaxPacketSize; - u8 bInterval; -}; - -struct UsbDeviceHID -{ - le_t bcdHID; - u8 bCountryCode; - u8 bNumDescriptors; - u8 bDescriptorType; - le_t wDescriptorLength; -}; - -struct UsbTransfer -{ - u32 assigned_number = 0; - u32 transfer_id = 0; - - s32 result = 0; - u32 count = 0; - UsbDeviceIsoRequest iso_request{}; - - std::vector setup_buf; - libusb_transfer* transfer = nullptr; - bool busy = false; - - // For control transfers - u8* control_destbuf = nullptr; - - // For fake transfers - bool fake = false; - u64 expected_time = 0; - s32 expected_result = 0; - u32 expected_count = 0; -}; - -// Usb descriptor helper -struct UsbDescriptorNode -{ - u8 bLength{}; - u8 bDescriptorType{}; - - union - { - UsbDeviceDescriptor _device; - UsbDeviceConfiguration _configuration; - UsbDeviceInterface _interface; - UsbDeviceEndpoint _endpoint; - UsbDeviceHID _hid; - u8 data[0xFF]{}; - }; - - std::vector subnodes; - - UsbDescriptorNode() {} - template - UsbDescriptorNode(u8 _bDescriptorType, const T& _data) - : bLength(sizeof(T) + 2), bDescriptorType(_bDescriptorType) - { - memcpy(data, &_data, sizeof(T)); - } - UsbDescriptorNode(u8 _bLength, u8 _bDescriptorType, const u8* _data) - : bLength(_bLength), bDescriptorType(_bDescriptorType) - { - memcpy(data, _data, _bLength - 2); - } - - UsbDescriptorNode& add_node(const UsbDescriptorNode& newnode) - { - subnodes.push_back(newnode); - return subnodes.back(); - } - - u32 get_size() const - { - u32 nodesize = bLength; - for (const auto& node : subnodes) - { - nodesize += node.get_size(); - } - return nodesize; - } - - u32 write_data(u8* ptr, u32 max_size) const - { - u32 size = std::min(bLength, max_size); - memcpy(ptr, this, size); - for (const auto& node : subnodes) - { - const u32 remaining = max_size - size; - if (remaining == 0) - break; - size += node.write_data(ptr + size, remaining); - } - return size; - } -}; - -class usb_device -{ -public: - usb_device(const std::array& location); - virtual ~usb_device() = default; - - virtual bool open_device() = 0; - - void get_location(u8* location) const; - virtual void read_descriptors(); - - virtual u32 get_configuration(u8* buf); - virtual bool set_configuration(u8 cfg_num); - virtual bool set_interface(u8 int_num); - - virtual void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) = 0; - virtual void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) = 0; - virtual void isochronous_transfer(UsbTransfer* transfer) = 0; - -public: - // device ID if the device has been ldded(0 otherwise) - u32 assigned_number = 0; - // base device descriptor, every other descriptor is a subnode - UsbDescriptorNode device; - -protected: - u8 current_config = 1; - u8 current_interface = 0; - std::array location{}; - -protected: - static u64 get_timestamp(); -}; - -class usb_device_passthrough : public usb_device -{ -public: - usb_device_passthrough(libusb_device* _device, libusb_device_descriptor& desc, const std::array& location); - ~usb_device_passthrough(); - - bool open_device() override; - void read_descriptors() override; - u32 get_configuration(u8* buf) override; - bool set_configuration(u8 cfg_num) override; - bool set_interface(u8 int_num) override; - 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; - void isochronous_transfer(UsbTransfer* transfer) override; - -protected: - void send_libusb_transfer(libusb_transfer* transfer); - -protected: - libusb_device* lusb_device = nullptr; - libusb_device_handle* lusb_handle = nullptr; -}; - -class usb_device_emulated : public usb_device -{ -public: - usb_device_emulated(const std::array& location); - usb_device_emulated(const UsbDeviceDescriptor& _device, const std::array& location); - - bool open_device() override; - 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; - void isochronous_transfer(UsbTransfer* transfer) override; - - // Emulated specific functions - void add_string(std::string str); - u32 get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size); - u32 get_status(bool self_powered, bool remote_wakeup, u8* buf, u32 buf_size); - -protected: - std::vector strings; -}; diff --git a/rpcs3/Emu/Io/usb_vfs.cpp b/rpcs3/Emu/Io/usb_vfs.cpp deleted file mode 100644 index cea02fb276..0000000000 --- a/rpcs3/Emu/Io/usb_vfs.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "stdafx.h" -#include "usb_vfs.h" - -LOG_CHANNEL(usb_vfs); - -usb_device_vfs::usb_device_vfs(const cfg::device_info& device_info, const std::array& location) - : usb_device_emulated(location) -{ - const auto [vid, pid] = device_info.get_usb_ids(); - - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0200, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x40, - .idVendor = vid, - .idProduct = pid, - .bcdDevice = pid, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - .bNumConfigurations = 0x01}); - - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 0x0020, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0x80, - .bMaxPower = 0x32})); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x02, - .bInterfaceClass = 0x08, - .bInterfaceSubClass = 0x06, - .bInterfaceProtocol = 0x50, - .iInterface = 0x00})); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x81, - .bmAttributes = 0x02, - .wMaxPacketSize = 0x0200, - .bInterval = 0xFF})); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x02, - .bmAttributes = 0x02, - .wMaxPacketSize = 0x0200, - .bInterval = 0xFF})); - - strings = {"SMI Corporation", "USB DISK", device_info.serial}; // Manufacturer, Product, SerialNumber -} - -usb_device_vfs::~usb_device_vfs() -{ -} diff --git a/rpcs3/Emu/Io/usb_vfs.h b/rpcs3/Emu/Io/usb_vfs.h deleted file mode 100644 index f21f79bef6..0000000000 --- a/rpcs3/Emu/Io/usb_vfs.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "Emu/Io/usb_device.h" -#include "util/Config.h" - -class usb_device_vfs : public usb_device_emulated -{ -public: - usb_device_vfs(const cfg::device_info& device_info, const std::array& location); - ~usb_device_vfs(); -}; diff --git a/rpcs3/Emu/Io/usio.cpp b/rpcs3/Emu/Io/usio.cpp deleted file mode 100644 index fc0318ca4a..0000000000 --- a/rpcs3/Emu/Io/usio.cpp +++ /dev/null @@ -1,691 +0,0 @@ -// v406 USIO emulator - -#include "stdafx.h" -#include "usio.h" -#include "Input/pad_thread.h" -#include "Emu/Io/usio_config.h" -#include "Emu/IdManager.h" - -LOG_CHANNEL(usio_log, "USIO"); - -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](usio_btn value) - { - switch (value) - { - case usio_btn::test: return "Test"; - case usio_btn::coin: return "Coin"; - case usio_btn::service: return "Service"; - case usio_btn::enter: return "Enter/Start"; - case usio_btn::up: return "Up"; - case usio_btn::down: return "Down"; - case usio_btn::left: return "Left"; - case usio_btn::right: return "Right"; - case usio_btn::taiko_hit_side_left: return "Taiko Hit Side Left"; - case usio_btn::taiko_hit_side_right: return "Taiko Hit Side Right"; - case usio_btn::taiko_hit_center_left: return "Taiko Hit Center Left"; - case usio_btn::taiko_hit_center_right: return "Taiko Hit Center Right"; - case usio_btn::tekken_button1: return "Tekken Button 1"; - case usio_btn::tekken_button2: return "Tekken Button 2"; - case usio_btn::tekken_button3: return "Tekken Button 3"; - case usio_btn::tekken_button4: return "Tekken Button 4"; - case usio_btn::tekken_button5: return "Tekken Button 5"; - case usio_btn::count: return "Count"; - } - - return unknown; - }); -} - -struct usio_memory -{ - std::vector backup_memory; - - usio_memory() = default; - usio_memory(const usio_memory&) = delete; - usio_memory& operator=(const usio_memory&) = delete; - - void init() - { - backup_memory.clear(); - backup_memory.resize(page_size * page_count); - } - - static constexpr usz page_size = 0x10000; - static constexpr usz page_count = 0x10; -}; - -usb_device_usio::usb_device_usio(const std::array& location) - : usb_device_emulated(location) -{ - // Initialize dependencies - g_fxo->need(); - - device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, - UsbDeviceDescriptor{ - .bcdUSB = 0x0110, - .bDeviceClass = 0xff, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0xff, - .bMaxPacketSize0 = 0x8, - .idVendor = 0x0b9a, - .idProduct = 0x0910, - .bcdDevice = 0x0910, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x00, - .bNumConfigurations = 0x01}); - - auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, - UsbDeviceConfiguration{ - .wTotalLength = 39, - .bNumInterfaces = 0x01, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = 0xc0, - .bMaxPower = 0x32 // ??? 100ma - })); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, - UsbDeviceInterface{ - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x03, - .bInterfaceClass = 0x00, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, - .iInterface = 0x00})); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x01, - .bmAttributes = 0x02, - .wMaxPacketSize = 0x0040, - .bInterval = 0x00})); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x82, - .bmAttributes = 0x02, - .wMaxPacketSize = 0x0040, - .bInterval = 0x00})); - - config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, - UsbDeviceEndpoint{ - .bEndpointAddress = 0x83, - .bmAttributes = 0x03, - .wMaxPacketSize = 0x0008, - .bInterval = 16})); - - load_backup(); -} - -usb_device_usio::~usb_device_usio() -{ - save_backup(); -} - -std::shared_ptr usb_device_usio::make_instance(u32, const std::array& location) -{ - return std::make_shared(location); -} - -u16 usb_device_usio::get_num_emu_devices() -{ - return 1; -} - -void usb_device_usio::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) - { - // default: - // Follow to default emulated handler - usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); - // break; - } -} - -extern bool is_input_allowed(); - -void usb_device_usio::load_backup() -{ - usio_memory& memory = g_fxo->get(); - memory.init(); - - fs::file usio_backup_file; - - if (!usio_backup_file.open(usio_backup_path, fs::read)) - { - usio_log.trace("Failed to load the USIO Backup file: %s", usio_backup_path); - return; - } - - const u64 file_size = memory.backup_memory.size(); - - if (usio_backup_file.size() != file_size) - { - usio_log.trace("Invalid USIO Backup file detected: %s", usio_backup_path); - return; - } - - usio_backup_file.read(memory.backup_memory.data(), file_size); -} - -void usb_device_usio::save_backup() -{ - if (!is_used) - return; - - fs::file usio_backup_file; - - if (!usio_backup_file.open(usio_backup_path, fs::create + fs::write + fs::lock)) - { - usio_log.error("Failed to save the USIO Backup file: %s", usio_backup_path); - return; - } - - const u64 file_size = g_fxo->get().backup_memory.size(); - - usio_backup_file.write(g_fxo->get().backup_memory.data(), file_size); - usio_backup_file.trunc(file_size); -} - -void usb_device_usio::translate_input_taiko() -{ - std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_pad_thread(); - - std::vector input_buf(0x60); - constexpr le_t c_hit = 0x1800; - le_t digital_input = 0; - - const auto translate_from_pad = [&](usz pad_number, usz player) - { - const usz offset = player * 8ULL; - auto& status = m_io_status[0]; - - if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) - { - const auto& cfg = ::at32(g_cfg_usio.players, pad_number); - cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) - { - switch (btn) - { - case usio_btn::test: - if (player != 0) - break; - if (pressed && !status.test_key_pressed) // Solve the need to hold the Test key - status.test_on = !status.test_on; - status.test_key_pressed = pressed; - break; - case usio_btn::coin: - if (player != 0) - break; - if (pressed && !status.coin_key_pressed) // Ensure only one coin is inserted each time the Coin key is pressed - status.coin_counter++; - status.coin_key_pressed = pressed; - break; - case usio_btn::service: - if (player == 0 && pressed) - digital_input |= 0x4000; - break; - case usio_btn::enter: - if (player == 0 && pressed) - digital_input |= 0x200; - break; - case usio_btn::up: - if (player == 0 && pressed) - digital_input |= 0x2000; - break; - case usio_btn::down: - if (player == 0 && pressed) - digital_input |= 0x1000; - break; - case usio_btn::taiko_hit_side_left: - if (pressed) - std::memcpy(input_buf.data() + 32 + offset, &c_hit, sizeof(u16)); - break; - case usio_btn::taiko_hit_center_right: - if (pressed) - std::memcpy(input_buf.data() + 36 + offset, &c_hit, sizeof(u16)); - break; - case usio_btn::taiko_hit_side_right: - if (pressed) - std::memcpy(input_buf.data() + 38 + offset, &c_hit, sizeof(u16)); - break; - case usio_btn::taiko_hit_center_left: - if (pressed) - std::memcpy(input_buf.data() + 34 + offset, &c_hit, sizeof(u16)); - break; - default: - break; - } - }); - } - - if (player == 0 && status.test_on) - digital_input |= 0x80; - }; - - for (usz i = 0; i < g_cfg_usio.players.size(); i++) - translate_from_pad(i, i); - - std::memcpy(input_buf.data(), &digital_input, sizeof(u16)); - std::memcpy(input_buf.data() + 16, &m_io_status[0].coin_counter, sizeof(u16)); - - response = std::move(input_buf); -} - -void usb_device_usio::translate_input_tekken() -{ - std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_pad_thread(); - - std::vector input_buf(0x180); - le_t digital_input[2]{}; - le_t digital_input_lm = 0; - - const auto translate_from_pad = [&](usz pad_number, usz player) - { - const usz shift = (player % 2) * 24ULL; - auto& status = m_io_status[player / 2]; - auto& input = digital_input[player / 2]; - - if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) - { - const auto& cfg = ::at32(g_cfg_usio.players, pad_number); - cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) - { - switch (btn) - { - case usio_btn::test: - if (player % 2 != 0) - break; - if (pressed && !status.test_key_pressed) // Solve the need to hold the Test button - status.test_on = !status.test_on; - status.test_key_pressed = pressed; - break; - case usio_btn::coin: - if (player % 2 != 0) - break; - if (pressed && !status.coin_key_pressed) // Ensure only one coin is inserted each time the Coin button is pressed - status.coin_counter++; - status.coin_key_pressed = pressed; - break; - case usio_btn::service: - if (player % 2 == 0 && pressed) - input |= 0x4000; - break; - case usio_btn::enter: - if (pressed) - { - input |= 0x800000ULL << shift; - if (player == 0) - digital_input_lm |= 0x800; - } - break; - case usio_btn::up: - if (pressed) - { - input |= 0x200000ULL << shift; - if (player == 0) - digital_input_lm |= 0x200; - } - break; - case usio_btn::down: - if (pressed) - { - input |= 0x100000ULL << shift; - if (player == 0) - digital_input_lm |= 0x400; - } - break; - case usio_btn::left: - if (pressed) - { - input |= 0x80000ULL << shift; - if (player == 0) - digital_input_lm |= 0x2000; - } - break; - case usio_btn::right: - if (pressed) - { - input |= 0x40000ULL << shift; - if (player == 0) - digital_input_lm |= 0x4000; - } - break; - case usio_btn::tekken_button1: - if (pressed) - { - input |= 0x20000ULL << shift; - if (player == 0) - digital_input_lm |= 0x100; - } - break; - case usio_btn::tekken_button2: - if (pressed) - input |= 0x10000ULL << shift; - break; - case usio_btn::tekken_button3: - if (pressed) - input |= 0x40000000ULL << shift; - break; - case usio_btn::tekken_button4: - if (pressed) - input |= 0x20000000ULL << shift; - break; - case usio_btn::tekken_button5: - if (pressed) - input |= 0x80000000ULL << shift; - break; - default: - break; - } - }); - } - - if (player % 2 == 0 && status.test_on) - { - input |= 0x80; - if (player == 0) - digital_input_lm |= 0x1000; - } - }; - - for (usz i = 0; i < g_cfg_usio.players.size(); i++) - translate_from_pad(i, i); - - for (usz i = 0; i < 2; i++) - { - std::memcpy(input_buf.data() - i * 0x80 + 0x100, &digital_input[i], sizeof(u64)); - std::memcpy(input_buf.data() - i * 0x80 + 0x100 + 0x10, &m_io_status[i].coin_counter, sizeof(u16)); - } - - std::memcpy(input_buf.data(), &digital_input_lm, sizeof(u16)); - - input_buf[2] = 0b00010000; // DIP switches, 8 in total - - response = std::move(input_buf); -} - -void usb_device_usio::usio_write(u8 channel, u16 reg, std::vector& data) -{ - const auto get_u16 = [&](std::string_view usio_func) -> u16 - { - if (data.size() != 2) - { - usio_log.error("data.size() is %d, expected 2 for get_u16 in %s", data.size(), usio_func); - } - return *reinterpret_cast*>(data.data()); - }; - - if (channel == 0) - { - switch (reg) - { - case 0x0002: - { - usio_log.trace("SetSystemError: 0x%04X", get_u16("SetSystemError")); - break; - } - case 0x000A: - { - if (get_u16("ClearSram") == 0x6666) - usio_log.trace("ClearSram"); - break; - } - case 0x0028: - { - usio_log.trace("SetExpansionMode: 0x%04X", get_u16("SetExpansionMode")); - break; - } - case 0x0048: - case 0x0058: - case 0x0068: - case 0x0078: - { - usio_log.trace("SetHopperRequest(Hopper: %d, Request: 0x%04X)", (reg - 0x48) / 0x10, get_u16("SetHopperRequest")); - break; - } - case 0x004A: - case 0x005A: - case 0x006A: - case 0x007A: - { - usio_log.trace("SetHopperRequest(Hopper: %d, Limit: 0x%04X)", (reg - 0x4A) / 0x10, get_u16("SetHopperLimit")); - break; - } - default: - { - usio_log.trace("Unhandled channel 0 register write(reg: 0x%04X, size: 0x%04X, data: %s)", reg, data.size(), fmt::buf_to_hexstring(data.data(), data.size())); - break; - } - } - } - else if (channel >= 2) - { - const u8 page = channel - 2; - usio_log.trace("Usio write of sram(page: 0x%02X, addr: 0x%04X, size: 0x%04X, data: %s)", page, reg, data.size(), fmt::buf_to_hexstring(data.data(), data.size())); - auto& memory = g_fxo->get().backup_memory; - const usz addr_end = reg + data.size(); - if (data.size() > 0 && page < usio_memory::page_count && addr_end <= usio_memory::page_size) - std::memcpy(&memory[usio_memory::page_size * page + reg], data.data(), data.size()); - else - usio_log.error("Usio sram invalid write operation(page: 0x%02X, addr: 0x%04X, size: 0x%04X, data: %s)", page, reg, data.size(), fmt::buf_to_hexstring(data.data(), data.size())); - } - else - { - // Channel 1 is the endpoint for firmware update. - // We are not using any firmware since this is emulation. - usio_log.trace("Unsupported write operation(channel: 0x%02X, addr: 0x%04X, size: 0x%04X, data: %s)", channel, reg, data.size(), fmt::buf_to_hexstring(data.data(), data.size())); - } -} - -void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) -{ - if (channel == 0) - { - switch (reg) - { - case 0x0000: - { - // Get Buffer, rarely gives a reply on real HW - // First U16 seems to be a timestamp of sort - // Purpose seems related to connectivity check - response = {0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - break; - } - case 0x0080: - { - // Card reader check - 1 - response = {0x02, 0x03, 0x06, 0x00, 0xFF, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00}; - break; - } - case 0x7000: - { - // Card reader check - 2 - // No data returned - break; - } - case 0x1000: - { - // Often called, gets input from usio for Tekken - translate_input_tekken(); - break; - } - case 0x1080: - { - // Often called, gets input from usio for Taiko - translate_input_taiko(); - break; - } - case 0x1800: - case 0x1880: - { - // Seems to contain a few extra bytes of info in addition to the firmware string - // Firmware - // "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG." - constexpr std::array info{0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x31, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x32, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - response = {info.begin() + (reg - 0x1800), info.end()}; - break; - } - default: - { - usio_log.trace("Unhandled channel 0 register read(reg: 0x%04X, size: 0x%04X)", reg, size); - break; - } - } - } - else if (channel >= 2) - { - const u8 page = channel - 2; - usio_log.trace("Usio read of sram(page: 0x%02X, addr: 0x%04X, size: 0x%04X)", page, reg, size); - auto& memory = g_fxo->get().backup_memory; - const usz addr_end = reg + size; - if (size > 0 && page < usio_memory::page_count && addr_end <= usio_memory::page_size) - response.insert(response.end(), memory.begin() + (usio_memory::page_size * page + reg), memory.begin() + (usio_memory::page_size * page + addr_end)); - else - usio_log.error("Usio sram invalid read operation(page: 0x%02X, addr: 0x%04X, size: 0x%04X)", page, reg, size); - } - else - { - // Channel 1 is the endpoint for firmware update. - // We are not using any firmware since this is emulation. - usio_log.trace("Unsupported read operation(channel: 0x%02X, addr: 0x%04X, size: 0x%04X)", channel, reg, size); - } - - response.resize(size); // Always resize the response vector to the given size -} - -void usb_device_usio::usio_init(u8 channel, u16 reg, u16 size) -{ - if (channel == 0) - { - switch (reg) - { - case 0x0008: - { - usio_log.trace("USIO Reset"); - break; - } - case 0x000A: - { - usio_log.trace("USIO ClearSram"); - g_fxo->get().init(); - break; - } - default: - { - usio_log.trace("Unhandled channel 0 register init(reg: 0x%04X, size: 0x%04X)", reg, size); - break; - } - } - } - else - { - usio_log.trace("Unsupported init operation(channel: 0x%02X, addr: 0x%04X, size: 0x%04X)", channel, reg, size); - } -} - -void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) -{ - constexpr u8 USIO_COMMAND_WRITE = 0x90; - constexpr u8 USIO_COMMAND_READ = 0x10; - constexpr u8 USIO_COMMAND_INIT = 0xA0; - - static bool expecting_data = false; - static std::vector usio_data; - static u32 response_seek = 0; - static u8 usio_channel = 0; - static u16 usio_register = 0; - static u16 usio_length = 0; - - transfer->fake = true; - transfer->expected_result = HC_CC_NOERR; - // The latency varies per operation but it doesn't seem to matter for this device so let's go fast! - transfer->expected_time = get_timestamp() + 1'000; - - is_used = true; - - switch (endpoint) - { - case 0x01: - { - // Write endpoint - transfer->expected_count = buf_size; - - if (expecting_data) - { - usio_data.insert(usio_data.end(), buf, buf + buf_size); - usio_length -= buf_size; - - if (usio_length == 0) - { - expecting_data = false; - usio_write(usio_channel, usio_register, usio_data); - } - return; - } - - // Commands - if (buf_size != 6) - { - usio_log.error("Expected a command but buf_size != 6"); - return; - } - - usio_channel = buf[0] & 0xF; - usio_register = *reinterpret_cast*>(&buf[2]); - usio_length = *reinterpret_cast*>(&buf[4]); - - if ((buf[0] & USIO_COMMAND_WRITE) == USIO_COMMAND_WRITE) - { - usio_log.trace("UsioWrite(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length); - if (((~(usio_register >> 8)) & 0xF0) != buf[1]) - { - usio_log.error("Invalid UsioWrite command"); - return; - } - expecting_data = true; - usio_data.clear(); - } - else if ((buf[0] & USIO_COMMAND_READ) == USIO_COMMAND_READ) - { - usio_log.trace("UsioRead(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length); - response_seek = 0; - response.clear(); - usio_read(usio_channel, usio_register, usio_length); - } - else if ((buf[0] & USIO_COMMAND_INIT) == USIO_COMMAND_INIT) - { - usio_log.trace("UsioInit(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length); - usio_init(usio_channel, usio_register, usio_length); - } - else - { - usio_log.error("Received an unexpected command: 0x%02X", buf[0]); - } - break; - } - case 0x82: - { - // Read endpoint - const u32 size = std::min(buf_size, static_cast(response.size() - response_seek)); - memcpy(buf, response.data() + response_seek, size); - response_seek += size; - transfer->expected_count = size; - break; - } - default: - usio_log.error("Unhandled endpoint: 0x%x", endpoint); - break; - } -} diff --git a/rpcs3/Emu/Io/usio.h b/rpcs3/Emu/Io/usio.h deleted file mode 100644 index 7a83e7a8ca..0000000000 --- a/rpcs3/Emu/Io/usio.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "Emu/system_utils.hpp" -#include "Emu/Io/usb_device.h" - -class usb_device_usio : public usb_device_emulated -{ -public: - usb_device_usio(const std::array& location); - ~usb_device_usio(); - - static std::shared_ptr make_instance(u32 controller_index, const std::array& location); - static u16 get_num_emu_devices(); - - 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; - -private: - void load_backup(); - void save_backup(); - void translate_input_taiko(); - void translate_input_tekken(); - void usio_write(u8 channel, u16 reg, std::vector& data); - void usio_read(u8 channel, u16 reg, u16 size); - void usio_init(u8 channel, u16 reg, u16 size); - -private: - bool is_used = false; - const std::string usio_backup_path = rpcs3::utils::get_hdd1_dir() + "/caches/usiobackup.bin"; - std::vector response; - - struct io_status - { - bool test_on = false; - bool test_key_pressed = false; - bool coin_key_pressed = false; - le_t coin_counter = 0; - }; - - std::array m_io_status; -}; diff --git a/rpcs3/Emu/Io/usio_config.h b/rpcs3/Emu/Io/usio_config.h deleted file mode 100644 index 5ce4fba929..0000000000 --- a/rpcs3/Emu/Io/usio_config.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "emulated_pad_config.h" - -enum class usio_btn -{ - test, - coin, - service, - enter, - up, - down, - left, - right, - taiko_hit_side_left, - taiko_hit_side_right, - taiko_hit_center_left, - taiko_hit_center_right, - tekken_button1, - tekken_button2, - tekken_button3, - tekken_button4, - tekken_button5, - - count -}; - -struct cfg_usio final : public emulated_pad_config -{ - cfg_usio(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} - - cfg_pad_btn test{this, "Test", usio_btn::test, pad_button::select}; - cfg_pad_btn coin{this, "Coin", usio_btn::coin, pad_button::L3}; - cfg_pad_btn service{this, "Service", usio_btn::service, pad_button::R3}; - cfg_pad_btn enter{this, "Enter/Start", usio_btn::enter, pad_button::start}; - cfg_pad_btn up{this, "Up", usio_btn::up, pad_button::dpad_up}; - cfg_pad_btn down{this, "Down", usio_btn::down, pad_button::dpad_down}; - cfg_pad_btn left{this, "Left", usio_btn::left, pad_button::dpad_left}; - cfg_pad_btn right{this, "Right", usio_btn::right, pad_button::dpad_right}; - cfg_pad_btn taiko_hit_side_left{this, "Taiko Hit Side Left", usio_btn::taiko_hit_side_left, pad_button::square}; - cfg_pad_btn taiko_hit_side_right{this, "Taiko Hit Side Right", usio_btn::taiko_hit_side_right, pad_button::circle}; - cfg_pad_btn taiko_hit_center_left{this, "Taiko Hit Center Left", usio_btn::taiko_hit_center_left, pad_button::triangle}; - cfg_pad_btn taiko_hit_center_right{this, "Taiko Hit Center Right", usio_btn::taiko_hit_center_right, pad_button::cross}; - cfg_pad_btn tekken_button1{this, "Tekken Button 1", usio_btn::tekken_button1, pad_button::square}; - cfg_pad_btn tekken_button2{this, "Tekken Button 2", usio_btn::tekken_button2, pad_button::triangle}; - cfg_pad_btn tekken_button3{this, "Tekken Button 3", usio_btn::tekken_button3, pad_button::cross}; - cfg_pad_btn tekken_button4{this, "Tekken Button 4", usio_btn::tekken_button4, pad_button::circle}; - cfg_pad_btn tekken_button5{this, "Tekken Button 5", usio_btn::tekken_button5, pad_button::R1}; -}; - -struct cfg_usios final : public emulated_pads_config -{ - cfg_usios() : emulated_pads_config("usio") {}; -}; - -extern cfg_usios g_cfg_usio; diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index e2349248b1..92530ea416 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "stdafx.h" #include "ds3_pad_handler.h" #include "Emu/Io/pad_config.h" @@ -616,3 +618,5 @@ void ds3_pad_handler::apply_pad_data(const pad_ensemble& binding) } } } + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ds3_pad_handler.h b/rpcs3/Input/ds3_pad_handler.h index 593381e9e1..e46c23daf6 100644 --- a/rpcs3/Input/ds3_pad_handler.h +++ b/rpcs3/Input/ds3_pad_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "hid_pad_handler.h" @@ -157,3 +158,5 @@ class ds3_pad_handler final : public hid_pad_handler std::unordered_map get_button_values(const std::shared_ptr& device) override; pad_preview_values get_preview_values(const std::unordered_map& data) override; }; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index 85d0bf84c7..1ab55525fa 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "stdafx.h" #include "ds4_pad_handler.h" #include "Emu/Io/pad_config.h" @@ -985,3 +987,5 @@ void ds4_pad_handler::apply_pad_data(const pad_ensemble& binding) } } } + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index 7efa0a648a..d5bde84b88 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "hid_pad_handler.h" @@ -197,3 +198,5 @@ class ds4_pad_handler final : public hid_pad_handler std::unordered_map get_button_values(const std::shared_ptr& device) override; pad_preview_values get_preview_values(const std::unordered_map& data) override; }; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/dualsense_pad_handler.cpp b/rpcs3/Input/dualsense_pad_handler.cpp index 3784c0c6b5..521459fc12 100644 --- a/rpcs3/Input/dualsense_pad_handler.cpp +++ b/rpcs3/Input/dualsense_pad_handler.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "stdafx.h" #include "dualsense_pad_handler.h" #include "Emu/Io/pad_config.h" @@ -1089,3 +1091,5 @@ u32 dualsense_pad_handler::get_battery_level(const std::string& padId) } return std::min(device->battery_level * 10 + 5, 100); // 10% per unit, starting with 0-9%. So 100% equals unit 10 } + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/dualsense_pad_handler.h b/rpcs3/Input/dualsense_pad_handler.h index 023a5b34cf..8ecb3acef4 100644 --- a/rpcs3/Input/dualsense_pad_handler.h +++ b/rpcs3/Input/dualsense_pad_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "hid_pad_handler.h" @@ -259,3 +260,5 @@ class dualsense_pad_handler final : public hid_pad_handler void get_extended_info(const pad_ensemble& binding) override; void apply_pad_data(const pad_ensemble& binding) override; }; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index fe5a226c7e..daec1ba303 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "hid_pad_handler.h" #include "ds3_pad_handler.h" #include "ds4_pad_handler.h" @@ -416,3 +418,5 @@ template class hid_pad_handler; template class hid_pad_handler; template class hid_pad_handler; template class hid_pad_handler; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h index 4bf2c29131..626c4b5f4d 100644 --- a/rpcs3/Input/hid_pad_handler.h +++ b/rpcs3/Input/hid_pad_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "Emu/Io/PadHandler.h" #include "util/CRC.h" @@ -142,3 +143,5 @@ class hid_pad_handler : public PadHandlerBase private: std::shared_ptr get_device(const std::string& device) override; }; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ps_move_calibration.cpp b/rpcs3/Input/ps_move_calibration.cpp index adff388756..733ec4afda 100644 --- a/rpcs3/Input/ps_move_calibration.cpp +++ b/rpcs3/Input/ps_move_calibration.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "stdafx.h" #include "ps_move_calibration.h" @@ -241,3 +243,5 @@ void psmove_parse_calibration(const reports::ps_move_calibration_blob& calibrati psmove_calibration_get_usb_accel_values(calibration, device); psmove_calibration_get_usb_gyro_values(calibration, device); } + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ps_move_calibration.h b/rpcs3/Input/ps_move_calibration.h index a1e362fa9f..4190314e3d 100644 --- a/rpcs3/Input/ps_move_calibration.h +++ b/rpcs3/Input/ps_move_calibration.h @@ -1,5 +1,8 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "ps_move_handler.h" void psmove_parse_calibration(const reports::ps_move_calibration_blob& calibration, ps_move_device& device); + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ps_move_handler.cpp b/rpcs3/Input/ps_move_handler.cpp index 97f1bc8acf..d79efcf5d0 100644 --- a/rpcs3/Input/ps_move_handler.cpp +++ b/rpcs3/Input/ps_move_handler.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "stdafx.h" #include "ps_move_handler.h" #include "ps_move_calibration.h" @@ -878,3 +880,5 @@ u32 ps_move_handler::get_battery_level(const std::string& padId) // 0 to 5 return std::clamp(device->battery_level * 20, 0, 100); } + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/ps_move_handler.h b/rpcs3/Input/ps_move_handler.h index 863bd23a6f..baf7efd7f0 100644 --- a/rpcs3/Input/ps_move_handler.h +++ b/rpcs3/Input/ps_move_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "hid_pad_handler.h" @@ -202,3 +203,5 @@ class ps_move_handler final : public hid_pad_handler void handle_external_device(const pad_ensemble& binding); }; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/skateboard_pad_handler.cpp b/rpcs3/Input/skateboard_pad_handler.cpp index 4dbfb580d0..7e0b36f6b2 100644 --- a/rpcs3/Input/skateboard_pad_handler.cpp +++ b/rpcs3/Input/skateboard_pad_handler.cpp @@ -1,3 +1,5 @@ +#ifndef WITHOUT_HIDAPI + #include "stdafx.h" #include "skateboard_pad_handler.h" #include "Emu/Io/pad_config.h" @@ -400,3 +402,5 @@ void skateboard_pad_handler::SetPadData(const std::string& padId, u8 player_id, // skateboard_log.error("SetPadData: send_output_report failed! Reason: %s", hid_error(device->hidDevice)); //} } + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/Input/skateboard_pad_handler.h b/rpcs3/Input/skateboard_pad_handler.h index a9bc8fd947..121d08fc4a 100644 --- a/rpcs3/Input/skateboard_pad_handler.h +++ b/rpcs3/Input/skateboard_pad_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifndef WITHOUT_HIDAPI #include "hid_pad_handler.h" @@ -188,3 +189,5 @@ class skateboard_pad_handler final : public hid_pad_handler void get_extended_info(const pad_ensemble& binding) override; void apply_pad_data(const pad_ensemble& binding) override; }; + +#endif // WITHOUT_HIDAPI diff --git a/rpcs3/util/JIT.h b/rpcs3/util/JIT.h index a43a74488e..9f30e4e718 100644 --- a/rpcs3/util/JIT.h +++ b/rpcs3/util/JIT.h @@ -45,6 +45,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #if defined(ARCH_X64) using native_asm = asmjit::x86::Assembler; using native_args = std::array; @@ -438,7 +442,7 @@ namespace asmjit template inline FT build_function_asm(std::string_view name, F&& builder, ::jit_runtime* custom_runtime = nullptr, bool reduced_size = false) { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif using namespace asmjit; diff --git a/rpcs3/util/JITASM.cpp b/rpcs3/util/JITASM.cpp index b18c309a91..c198a506ab 100644 --- a/rpcs3/util/JITASM.cpp +++ b/rpcs3/util/JITASM.cpp @@ -307,7 +307,7 @@ void jit_runtime::initialize() void jit_runtime::finalize() noexcept { -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(false); #endif // Reset JIT memory @@ -325,7 +325,7 @@ void jit_runtime::finalize() noexcept std::memcpy(alloc(s_code_init.size(), 1, true), s_code_init.data(), s_code_init.size()); std::memcpy(alloc(s_data_init.size(), 1, false), s_data_init.data(), s_data_init.size()); -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) && !(defined(TARGET_OS_IPHONE) && defined(TARGET_OS_SIMULATOR)) pthread_jit_write_protect_np(true); #endif #ifdef ARCH_ARM64