From 59a17db6c42b55792e1712eb9e83a22dd2d68076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 7 Sep 2016 23:39:46 +0200 Subject: [PATCH 1/8] Add a __LIBUSB__ define This allows us to only check if __LIBUSB__ is defined, which is cleaner than checking for __LIBUSB__ and _WIN32. --- Source/Core/Core/Core.cpp | 6 +++--- Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp | 4 ++-- Source/VSProps/Base.props | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 73b4079a80..b8cd1e2733 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -297,7 +297,7 @@ void Stop() // - Hammertime! g_video_backend->Video_ExitLoop(); } -#if defined(__LIBUSB__) || defined(_WIN32) +#if defined(__LIBUSB__) GCAdapter::ResetRumble(); #endif @@ -698,7 +698,7 @@ void SetState(EState state) // stopped (including the CPU). CPU::EnableStepping(true); // Break Wiimote::Pause(); -#if defined(__LIBUSB__) || defined(_WIN32) +#if defined(__LIBUSB__) GCAdapter::ResetRumble(); #endif break; @@ -818,7 +818,7 @@ bool PauseAndLock(bool do_lock, bool unpause_on_unlock) // (s_efbAccessRequested). Fifo::PauseAndLock(do_lock, false); -#if defined(__LIBUSB__) || defined(_WIN32) +#if defined(__LIBUSB__) GCAdapter::ResetRumble(); #endif diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index d7f655c105..e52273f673 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -54,7 +54,7 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h" -#if defined(__LIBUSB__) || defined(_WIN32) +#if defined(__LIBUSB__) #include "Core/IPC_HLE/WII_IPC_HLE_Device_hid.h" #endif @@ -151,7 +151,7 @@ void Reinit() AddDevice("/dev/usb/ven"); AddDevice("/dev/sdio/slot0"); AddDevice("/dev/sdio/slot1"); -#if defined(__LIBUSB__) || defined(_WIN32) +#if defined(__LIBUSB__) AddDevice("/dev/usb/hid"); #else AddDevice("/dev/usb/hid"); diff --git a/Source/VSProps/Base.props b/Source/VSProps/Base.props index 4d4c080c3e..66013cc4a9 100644 --- a/Source/VSProps/Base.props +++ b/Source/VSProps/Base.props @@ -51,7 +51,7 @@ $(ExternalsDir)xxhash;%(AdditionalIncludeDirectories) $(ExternalsDir)zlib;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - USE_UPNP;%(PreprocessorDefinitions) + USE_UPNP;__LIBUSB__;%(PreprocessorDefinitions) PSAPI_VERSION=1;_M_X86=1;%(PreprocessorDefinitions) SFML_STATIC;%(PreprocessorDefinitions) CURL_STATICLIB;%(PreprocessorDefinitions) From 4b47997cf81e3726f203bef045e5d211a6bcc605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 23 Aug 2016 16:19:30 +0200 Subject: [PATCH 2/8] Add ability to passthrough a Bluetooth adapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the ability to passthrough a whole Bluetooth adapter and skip the majority of the Bluetooth emulation code. We use libusb to send HCI commands, receive HCI events and transfer ACL data directly to the first adapter that is found or to a specific adapter (if configured to) This is possible because the Wii's Bluetooth module is actually just a pretty standard Bluetooth adapter… …except for two vendor-specific commands, for which replies are faked, and also for the sync button. This adds a hotkey that works in the exact same way as the sync button would on a Wii: it triggers an HCI event, which emulated software interpret as a command to perform a BT inquiry. This commit also changes the UI code to expose passthrough mode and WII_IPC_HLE to be a bit more thread safe (for the device map). --- Source/Core/Core/CMakeLists.txt | 7 +- Source/Core/Core/ConfigManager.cpp | 20 + Source/Core/Core/ConfigManager.h | 7 + Source/Core/Core/Core.cpp | 4 +- Source/Core/Core/Core.vcxproj | 12 +- Source/Core/Core/Core.vcxproj.filters | 22 +- .../Core/Core/HW/WiimoteReal/WiimoteReal.cpp | 3 +- Source/Core/Core/HotkeyManager.cpp | 1 + Source/Core/Core/HotkeyManager.h | 1 + Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp | 33 +- .../Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 37 +- .../WII_IPC_HLE_Device_usb_bt_base.cpp | 48 +++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h | 75 ++++ ....cpp => WII_IPC_HLE_Device_usb_bt_emu.cpp} | 244 ++++++------ ..._usb.h => WII_IPC_HLE_Device_usb_bt_emu.h} | 61 +-- .../WII_IPC_HLE_Device_usb_bt_real.cpp | 370 ++++++++++++++++++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h | 83 ++++ .../WII_IPC_HLE_Device_usb_bt_stub.cpp | 24 ++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h | 24 ++ .../IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp | 2 +- .../Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp | 22 +- .../Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h | 10 +- Source/Core/Core/Movie.cpp | 5 +- Source/Core/Core/NetPlayClient.cpp | 2 +- Source/Core/Core/State.cpp | 2 +- .../Core/DolphinWX/ControllerConfigDiag.cpp | 106 +++-- Source/Core/DolphinWX/ControllerConfigDiag.h | 63 ++- Source/Core/DolphinWX/DolphinWX.vcxproj | 2 +- Source/Core/DolphinWX/Frame.cpp | 10 + Source/Core/DolphinWX/FrameTools.cpp | 22 +- Source/Core/DolphinWX/MainNoGUI.cpp | 5 +- 31 files changed, 1055 insertions(+), 272 deletions(-) create mode 100644 Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp create mode 100644 Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h rename Source/Core/Core/IPC_HLE/{WII_IPC_HLE_Device_usb.cpp => WII_IPC_HLE_Device_usb_bt_emu.cpp} (88%) rename Source/Core/Core/IPC_HLE/{WII_IPC_HLE_Device_usb.h => WII_IPC_HLE_Device_usb_bt_emu.h} (81%) create mode 100644 Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp create mode 100644 Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h create mode 100644 Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.cpp create mode 100644 Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 5250837e6f..8d62fc0668 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -145,7 +145,9 @@ set(SRCS ActionReplay.cpp IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp IPC_HLE/WII_IPC_HLE_Device_stm.cpp IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp - IPC_HLE/WII_IPC_HLE_Device_usb.cpp + IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp + IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp + IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.cpp IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp IPC_HLE/WII_IPC_HLE_WiiMote.cpp @@ -243,7 +245,8 @@ set(LIBS if(LIBUSB_FOUND) # Using shared LibUSB set(LIBS ${LIBS} ${LIBUSB_LIBRARIES}) - set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp) + set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp + IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp) endif(LIBUSB_FOUND) set(LIBS ${LIBS} ${MBEDTLS_LIBRARIES}) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index ec198b2837..6e896658ef 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -67,6 +67,7 @@ void SConfig::SaveSettings() SaveFifoPlayerSettings(ini); SaveAnalyticsSettings(ini); SaveNetworkSettings(ini); + SaveBluetoothPassthroughSettings(ini); ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); m_SYSCONF->Save(); @@ -322,6 +323,15 @@ void SConfig::SaveAnalyticsSettings(IniFile& ini) analytics->Set("PermissionAsked", m_analytics_permission_asked); } +void SConfig::SaveBluetoothPassthroughSettings(IniFile& ini) +{ + IniFile::Section* section = ini.GetOrCreateSection("BluetoothPassthrough"); + + section->Set("Enabled", m_bt_passthrough_enabled); + section->Set("VID", m_bt_passthrough_vid); + section->Set("PID", m_bt_passthrough_pid); +} + void SConfig::LoadSettings() { INFO_LOG(BOOT, "Loading Settings from %s", File::GetUserPath(F_DOLPHINCONFIG_IDX).c_str()); @@ -339,6 +349,7 @@ void SConfig::LoadSettings() LoadFifoPlayerSettings(ini); LoadNetworkSettings(ini); LoadAnalyticsSettings(ini); + LoadBluetoothPassthroughSettings(ini); m_SYSCONF = new SysConf(); } @@ -604,6 +615,15 @@ void SConfig::LoadAnalyticsSettings(IniFile& ini) analytics->Get("PermissionAsked", &m_analytics_permission_asked, false); } +void SConfig::LoadBluetoothPassthroughSettings(IniFile& ini) +{ + IniFile::Section* section = ini.GetOrCreateSection("BluetoothPassthrough"); + + section->Get("Enabled", &m_bt_passthrough_enabled, false); + section->Get("VID", &m_bt_passthrough_vid, -1); + section->Get("PID", &m_bt_passthrough_pid, -1); +} + void SConfig::LoadDefaults() { bEnableDebugging = false; diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 001417cb1c..2bb649fcbc 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -143,6 +143,11 @@ struct SConfig : NonCopyable bool m_analytics_enabled = false; bool m_analytics_permission_asked = false; + // Bluetooth passthrough mode settings + bool m_bt_passthrough_enabled = false; + int m_bt_passthrough_pid = -1; + int m_bt_passthrough_vid = -1; + // Fifo Player related settings bool bLoopFifoReplay = true; @@ -325,6 +330,7 @@ private: void SaveFifoPlayerSettings(IniFile& ini); void SaveNetworkSettings(IniFile& ini); void SaveAnalyticsSettings(IniFile& ini); + void SaveBluetoothPassthroughSettings(IniFile& ini); void LoadGeneralSettings(IniFile& ini); void LoadInterfaceSettings(IniFile& ini); @@ -337,6 +343,7 @@ private: void LoadFifoPlayerSettings(IniFile& ini); void LoadNetworkSettings(IniFile& ini); void LoadAnalyticsSettings(IniFile& ini); + void LoadBluetoothPassthroughSettings(IniFile& ini); static SConfig* m_Instance; }; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index b8cd1e2733..071302e17f 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -52,7 +52,7 @@ #include "Core/HW/SystemTimers.h" #include "Core/HW/VideoInterface.h" #include "Core/HW/Wiimote.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/IPC_HLE/WII_Socket.h" #include "Core/Movie.h" @@ -528,7 +528,7 @@ void EmuThread() } // Load and Init Wiimotes - only if we are booting in Wii mode - if (core_parameter.bWii) + if (core_parameter.bWii && !SConfig::GetInstance().m_bt_passthrough_enabled) { if (init_controllers) Wiimote::Initialize(s_window_handle, !s_state_filename.empty() ? diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index f0a54a74f3..62f953c2fe 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -185,7 +185,12 @@ - + + + + 4200;%(DisableSpecificWarnings) + + @@ -389,7 +394,10 @@ - + + + + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 082b302901..5479aee662 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -591,7 +591,16 @@ IPC HLE %28IOS/Starlet%29\USB - + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote + + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote + + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote @@ -1148,7 +1157,16 @@ IPC HLE %28IOS/Starlet%29\USB - + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote + + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote + + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote + + IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index e455047a66..1e780d5c56 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -702,7 +702,8 @@ void Initialize(::Wiimote::InitializeMode init_mode) g_wiimote_scanner.StartThread(); } - if (SConfig::GetInstance().m_WiimoteContinuousScanning) + if (SConfig::GetInstance().m_WiimoteContinuousScanning && + !SConfig::GetInstance().m_bt_passthrough_enabled) g_wiimote_scanner.SetScanMode(WiimoteScanMode::CONTINUOUSLY_SCAN); else g_wiimote_scanner.SetScanMode(WiimoteScanMode::DO_NOT_SCAN); diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index 8e757384ab..a97c87ae25 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -32,6 +32,7 @@ const std::string hotkey_labels[] = { _trans("Take Screenshot"), _trans("Exit"), + _trans("Press Sync Button"), _trans("Connect Wiimote 1"), _trans("Connect Wiimote 2"), _trans("Connect Wiimote 3"), diff --git a/Source/Core/Core/HotkeyManager.h b/Source/Core/Core/HotkeyManager.h index b8934dd79d..45dfc6474f 100644 --- a/Source/Core/Core/HotkeyManager.h +++ b/Source/Core/Core/HotkeyManager.h @@ -31,6 +31,7 @@ enum Hotkey HK_SCREENSHOT, HK_EXIT, + HK_TRIGGER_SYNC_BUTTON, HK_WIIMOTE1_CONNECT, HK_WIIMOTE2_CONNECT, HK_WIIMOTE3_CONNECT, diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index e52273f673..2cd0c130ac 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -22,6 +22,7 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC #include #include +#include #include #include @@ -50,7 +51,8 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC #include "Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_stm.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h" @@ -64,6 +66,7 @@ namespace WII_IPC_HLE_Interface { typedef std::map> TDeviceMap; static TDeviceMap g_DeviceMap; +static std::mutex g_device_map_mutex; // STATE_TO_SAVE #define IPC_MAX_FDS 0x18 @@ -122,13 +125,18 @@ std::shared_ptr AddDevice(const char* deviceName) void Reinit() { + std::lock_guard lock(g_device_map_mutex); _assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "Reinit called while already initialized"); CWII_IPC_HLE_Device_es::m_ContentFile = ""; num_devices = 0; // Build hardware devices - AddDevice("/dev/usb/oh1/57e/305"); + if (!SConfig::GetInstance().m_bt_passthrough_enabled) + AddDevice("/dev/usb/oh1/57e/305"); + else + AddDevice("/dev/usb/oh1/57e/305"); + AddDevice("/dev/stm/immediate"); AddDevice("/dev/stm/eventhook"); AddDevice("/dev/fs"); @@ -188,19 +196,21 @@ void Reset(bool _bHard) in_use = false; } - for (const auto& entry : g_DeviceMap) { - if (entry.second) + std::lock_guard lock(g_device_map_mutex); + for (const auto& entry : g_DeviceMap) { - // Force close - entry.second->Close(0, true); + if (entry.second) + { + // Force close + entry.second->Close(0, true); + } } + + if (_bHard) + g_DeviceMap.clear(); } - if (_bHard) - { - g_DeviceMap.clear(); - } request_queue.clear(); reply_queue.clear(); @@ -214,6 +224,7 @@ void Shutdown() void SetDefaultContentFile(const std::string& _rFilename) { + std::lock_guard lock(g_device_map_mutex); for (const auto& entry : g_DeviceMap) { if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0) @@ -251,6 +262,7 @@ int getFreeDeviceId() std::shared_ptr GetDeviceByName(const std::string& _rDeviceName) { + std::lock_guard lock(g_device_map_mutex); for (const auto& entry : g_DeviceMap) { if (entry.second && entry.second->GetDeviceName() == _rDeviceName) @@ -264,6 +276,7 @@ std::shared_ptr GetDeviceByName(const std::string& _rDevice std::shared_ptr AccessDeviceByID(u32 _ID) { + std::lock_guard lock(g_device_map_mutex); if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) { return g_DeviceMap[_ID]; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index 8ffaffccc9..12a48e41b0 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -47,7 +47,7 @@ #include "Core/ConfigManager.h" #include "Core/HW/DVDInterface.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/Movie.h" #include "Core/PowerPC/PowerPC.h" @@ -998,28 +998,33 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) } else { - CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer(); - size_t size = s_Usb->m_WiiMotes.size(); - bool* wiiMoteConnected = new bool[size]; - for (unsigned int i = 0; i < size; i++) - wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); + bool* wiiMoteConnected = new bool[MAX_BBMOTES]; + if (!SConfig::GetInstance().m_bt_passthrough_enabled) + { + CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* s_Usb = GetUsbPointer(); + for (unsigned int i = 0; i < MAX_BBMOTES; i++) + wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); + } WII_IPC_HLE_Interface::Reset(true); WII_IPC_HLE_Interface::Reinit(); - s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++) + + if (!SConfig::GetInstance().m_bt_passthrough_enabled) { - if (wiiMoteConnected[i]) + CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* s_Usb = GetUsbPointer(); + for (unsigned int i = 0; i < MAX_BBMOTES; i++) { - s_Usb->m_WiiMotes[i].Activate(false); - s_Usb->m_WiiMotes[i].Activate(true); - } - else - { - s_Usb->m_WiiMotes[i].Activate(false); + if (wiiMoteConnected[i]) + { + s_Usb->m_WiiMotes[i].Activate(false); + s_Usb->m_WiiMotes[i].Activate(true); + } + else + { + s_Usb->m_WiiMotes[i].Activate(false); + } } } - delete[] wiiMoteConnected; WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp new file mode 100644 index 0000000000..85e2095fa3 --- /dev/null +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp @@ -0,0 +1,48 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" +#include "Common/Assert.h" +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/HW/Memmap.h" + +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_base::IOCtl(u32 command_address) +{ + // NeoGamma (homebrew) is known to use this path. + ERROR_LOG(WII_IPC_WIIMOTE, "Bad IOCtl to /dev/usb/oh1/57e/305"); + Memory::Write_U32(FS_EINVAL, command_address + 4); + return GetDefaultReply(); +} + +CWII_IPC_HLE_Device_usb_oh1_57e_305_base::CtrlMessage::CtrlMessage(const SIOCtlVBuffer& cmd_buffer) +{ + request_type = Memory::Read_U8(cmd_buffer.InBuffer[0].m_Address); + request = Memory::Read_U8(cmd_buffer.InBuffer[1].m_Address); + value = Common::swap16(Memory::Read_U16(cmd_buffer.InBuffer[2].m_Address)); + index = Common::swap16(Memory::Read_U16(cmd_buffer.InBuffer[3].m_Address)); + length = Common::swap16(Memory::Read_U16(cmd_buffer.InBuffer[4].m_Address)); + payload_addr = cmd_buffer.PayloadBuffer[0].m_Address; + address = cmd_buffer.m_Address; +} + +CWII_IPC_HLE_Device_usb_oh1_57e_305_base::CtrlBuffer::CtrlBuffer(const SIOCtlVBuffer& cmd_buffer, + const u32 command_address) +{ + m_endpoint = Memory::Read_U8(cmd_buffer.InBuffer[0].m_Address); + m_length = Memory::Read_U16(cmd_buffer.InBuffer[1].m_Address); + m_payload_addr = cmd_buffer.PayloadBuffer[0].m_Address; + m_cmd_address = command_address; +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_base::CtrlBuffer::FillBuffer(const u8* src, + const size_t size) const +{ + _dbg_assert_msg_(WII_IPC_WIIMOTE, size <= m_length, "FillBuffer: size %li > payload length %i", + size, m_length); + Memory::CopyToEmu(m_payload_addr, src, size); +} diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h new file mode 100644 index 0000000000..2b7b230e1c --- /dev/null +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h @@ -0,0 +1,75 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device.h" + +class CWII_IPC_HLE_Device_usb_oh1_57e_305_base : public IWII_IPC_HLE_Device +{ +public: + CWII_IPC_HLE_Device_usb_oh1_57e_305_base(u32 device_id, const std::string& device_name) + : IWII_IPC_HLE_Device(device_id, device_name) + { + } + virtual ~CWII_IPC_HLE_Device_usb_oh1_57e_305_base() override = default; + + virtual IPCCommandResult Open(u32 command_address, u32 mode) override = 0; + virtual IPCCommandResult Close(u32 command_address, bool force) override = 0; + IPCCommandResult IOCtl(u32 command_address) override; + virtual IPCCommandResult IOCtlV(u32 command_address) override = 0; + + virtual void DoState(PointerWrap& p) override = 0; + virtual u32 Update() override = 0; + + virtual void UpdateSyncButtonState(bool is_held) {} + virtual void TriggerSyncButtonPressedEvent() {} + virtual void TriggerSyncButtonHeldEvent() {} +protected: + enum USBIOCtl + { + USBV0_IOCTL_CTRLMSG = 0, + USBV0_IOCTL_BLKMSG = 1, + USBV0_IOCTL_INTRMSG = 2, + }; + + enum USBEndpoint + { + HCI_CTRL = 0x00, + HCI_EVENT = 0x81, + ACL_DATA_IN = 0x82, + ACL_DATA_OUT = 0x02 + }; + + struct CtrlMessage + { + CtrlMessage() = default; + CtrlMessage(const SIOCtlVBuffer& cmd_buffer); + + u8 request_type; + u8 request; + u16 value; + u16 index; + u16 length; + u32 payload_addr; + u32 address; + }; + + class CtrlBuffer + { + public: + CtrlBuffer() = default; + CtrlBuffer(const SIOCtlVBuffer& cmd_buffer, u32 command_address); + + void FillBuffer(const u8* src, size_t size) const; + void SetRetVal(const u32 retval) const { Memory::Write_U32(retval, m_cmd_address + 4); } + bool IsValid() const { return m_cmd_address != 0; } + void Invalidate() { m_cmd_address = m_payload_addr = 0; } + u8 m_endpoint; + u16 m_length; + u32 m_payload_addr; + u32 m_cmd_address; + }; +}; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp similarity index 88% rename from Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp rename to Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp index 17cf062ec4..46a3669f54 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp @@ -12,12 +12,12 @@ #include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/Movie.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" -void CWII_IPC_HLE_Device_usb_oh1_57e_305::EnqueueReply(u32 CommandAddress) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::EnqueueReply(u32 CommandAddress) { // IOS seems to write back the command that was responded to in the FD field, this // class does not overwrite the command so it is safe to read back. @@ -29,10 +29,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::EnqueueReply(u32 CommandAddress) } // The device class -CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305( +CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CWII_IPC_HLE_Device_usb_oh1_57e_305_emu( u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_ScanEnable(0), m_HCIEndpoint(0), - m_ACLEndpoint(0), m_last_ticks(0) + : CWII_IPC_HLE_Device_usb_oh1_57e_305_base(_DeviceID, _rDeviceName) { SysConf* sysconf; std::unique_ptr owned_sysconf; @@ -115,14 +114,23 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305( Host_SetWiiMoteConnectionState(0); } -CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305() +CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::~CWII_IPC_HLE_Device_usb_oh1_57e_305_emu() { m_WiiMotes.clear(); SetUsbPointer(nullptr); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap& p) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::DoState(PointerWrap& p) { + bool passthrough_bluetooth = false; + p.Do(passthrough_bluetooth); + if (passthrough_bluetooth && p.GetMode() == PointerWrap::MODE_READ) + { + Core::DisplayMessage("State needs Bluetooth passthrough to be enabled. Aborting load.", 4000); + p.SetMode(PointerWrap::MODE_VERIFY); + return; + } + p.Do(m_Active); p.Do(m_ControllerBD); p.Do(m_CtrlSetup); @@ -139,35 +147,35 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap& p) m_WiiMotes[i].DoState(p); } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::RemoteDisconnect(u16 _connectionHandle) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::RemoteDisconnect(u16 _connectionHandle) { return SendEventDisconnect(_connectionHandle, 0x13); } -IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::Open(u32 _CommandAddress, u32 _Mode) +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::Open(u32 _CommandAddress, u32 _Mode) { m_ScanEnable = 0; m_last_ticks = 0; memset(m_PacketCount, 0, sizeof(m_PacketCount)); - m_HCIEndpoint.m_address = 0; - m_ACLEndpoint.m_address = 0; + m_HCIEndpoint.m_cmd_address = 0; + m_ACLEndpoint.m_cmd_address = 0; Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); m_Active = true; return GetDefaultReply(); } -IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::Close(u32 _CommandAddress, bool _bForce) +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::Close(u32 _CommandAddress, bool _bForce) { m_ScanEnable = 0; m_last_ticks = 0; memset(m_PacketCount, 0, sizeof(m_PacketCount)); - m_HCIEndpoint.m_address = 0; - m_ACLEndpoint.m_address = 0; + m_HCIEndpoint.m_cmd_address = 0; + m_ACLEndpoint.m_cmd_address = 0; if (!_bForce) Memory::Write_U32(0, _CommandAddress + 4); @@ -175,7 +183,7 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::Close(u32 _CommandAddress, return GetDefaultReply(); } -IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtl(u32 _CommandAddress) +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::IOCtl(u32 _CommandAddress) { // NeoGamma (homebrew) is known to use this path. ERROR_LOG(WII_IPC_WIIMOTE, "Bad IOCtl in CWII_IPC_HLE_Device_usb_oh1_57e_305"); @@ -183,7 +191,7 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtl(u32 _CommandAddress) return GetDefaultReply(); } -IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress) +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::IOCtlV(u32 _CommandAddress) { /* Memory::Write_U8(255, 0x80149950); // BTM LOG // 3 logs L2Cap // 4 logs l2_csm$ @@ -240,8 +248,8 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress case USBV0_IOCTL_BLKMSG: { - u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); - switch (Command) + const CtrlBuffer ctrl(CommandBuffer, _CommandAddress); + switch (ctrl.m_endpoint) { case ACL_DATA_OUT: // ACL data is received from the stack { @@ -249,20 +257,15 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress // Here we only need to record the command address in case we need to delay the reply m_ACLSetup = CommandBuffer.m_Address; -#if defined(_DEBUG) || defined(DEBUGFAST) - DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, - CommandBuffer.NumberPayloadBuffer); -#endif + const auto* acl_header = + reinterpret_cast(Memory::GetPointer(ctrl.m_payload_addr)); - CtrlBuffer BulkBuffer(_CommandAddress); - hci_acldata_hdr_t* pACLHeader = (hci_acldata_hdr_t*)Memory::GetPointer(BulkBuffer.m_buffer); + _dbg_assert_(WII_IPC_WIIMOTE, HCI_BC_FLAG(acl_header->con_handle) == HCI_POINT2POINT); + _dbg_assert_(WII_IPC_WIIMOTE, HCI_PB_FLAG(acl_header->con_handle) == HCI_PACKET_START); - _dbg_assert_(WII_IPC_WIIMOTE, HCI_BC_FLAG(pACLHeader->con_handle) == HCI_POINT2POINT); - _dbg_assert_(WII_IPC_WIIMOTE, HCI_PB_FLAG(pACLHeader->con_handle) == HCI_PACKET_START); - - SendToDevice(HCI_CON_HANDLE(pACLHeader->con_handle), - Memory::GetPointer(BulkBuffer.m_buffer + sizeof(hci_acldata_hdr_t)), - pACLHeader->length); + SendToDevice(HCI_CON_HANDLE(acl_header->con_handle), + Memory::GetPointer(ctrl.m_payload_addr + sizeof(hci_acldata_hdr_t)), + acl_header->length); _SendReply = true; } @@ -270,7 +273,7 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress case ACL_DATA_IN: // We are given an ACL buffer to fill { - CtrlBuffer temp(_CommandAddress); + CtrlBuffer temp(CommandBuffer, _CommandAddress); m_ACLEndpoint = temp; DEBUG_LOG(WII_IPC_WIIMOTE, "ACL_DATA_IN: 0x%08x ", _CommandAddress); @@ -279,7 +282,7 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress default: { - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_BLKMSG: %x", Command); + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_BLKMSG: %x", ctrl.m_endpoint); } break; } @@ -288,17 +291,17 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress case USBV0_IOCTL_INTRMSG: { - u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); - if (Command == HCI_EVENT) // We are given a HCI buffer to fill + const CtrlBuffer ctrl(CommandBuffer, _CommandAddress); + if (ctrl.m_endpoint == HCI_EVENT) // We are given a HCI buffer to fill { - CtrlBuffer temp(_CommandAddress); + CtrlBuffer temp(CommandBuffer, _CommandAddress); m_HCIEndpoint = temp; DEBUG_LOG(WII_IPC_WIIMOTE, "HCI_EVENT: 0x%08x ", _CommandAddress); } else { - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_INTRMSG: %x", Command); + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_INTRMSG: %x", ctrl.m_endpoint); } } break; @@ -329,7 +332,8 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress } // Here we handle the USBV0_IOCTL_BLKMSG Ioctlv -void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendToDevice(u16 _ConnectionHandle, u8* _pData, + u32 _Size) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_ConnectionHandle); if (pWiiMote == nullptr) @@ -340,7 +344,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8 pWiiMote->ExecuteL2capCmd(_pData, _Size); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::IncDataPacket(u16 _ConnectionHandle) { m_PacketCount[_ConnectionHandle & 0xff]++; @@ -357,18 +361,18 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle) // Here we send ACL packets to CPU. They will consist of header + data. // The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041. -void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 connection_handle, const u8* data, - u32 size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendACLPacket(u16 connection_handle, const u8* data, + u32 size) { DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", connection_handle); if (m_ACLEndpoint.IsValid() && !m_HCIEndpoint.IsValid() && m_EventQueue.empty()) { DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint valid, sending packet to %08x", - m_ACLEndpoint.m_address); + m_ACLEndpoint.m_cmd_address); hci_acldata_hdr_t* header = - reinterpret_cast(Memory::GetPointer(m_ACLEndpoint.m_buffer)); + reinterpret_cast(Memory::GetPointer(m_ACLEndpoint.m_payload_addr)); header->con_handle = HCI_MK_CON_HANDLE(connection_handle, HCI_PACKET_START, HCI_POINT2POINT); header->length = size; @@ -376,7 +380,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 connection_handle, c memcpy(reinterpret_cast(header) + sizeof(hci_acldata_hdr_t), data, header->length); m_ACLEndpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); - EnqueueReply(m_ACLEndpoint.m_address); + EnqueueReply(m_ACLEndpoint.m_cmd_address); m_ACLEndpoint.Invalidate(); } else @@ -391,7 +395,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 connection_handle, c // // Our WII_IPC_HLE is so efficient that we could fill the buffer immediately // rather than enqueue it to some other memory and this will do good for StateSave -void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _event) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::AddEventToQueue(const SQueuedEvent& _event) { DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x completed...", ((hci_event_hdr_t*)_event.m_buffer)->event); @@ -401,11 +405,11 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e if (m_EventQueue.empty()) // fast path :) { DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint valid, sending packet to %08x", - m_HCIEndpoint.m_address); + m_HCIEndpoint.m_cmd_address); m_HCIEndpoint.FillBuffer(_event.m_buffer, _event.m_size); m_HCIEndpoint.SetRetVal(_event.m_size); // Send a reply to indicate HCI buffer is filled - EnqueueReply(m_HCIEndpoint.m_address); + EnqueueReply(m_HCIEndpoint.m_cmd_address); m_HCIEndpoint.Invalidate(); } else // push new one, pop oldest @@ -417,11 +421,11 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x " "being written from queue (%zu) to %08x...", ((hci_event_hdr_t*)event.m_buffer)->event, m_EventQueue.size() - 1, - m_HCIEndpoint.m_address); + m_HCIEndpoint.m_cmd_address); m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); m_HCIEndpoint.SetRetVal(event.m_size); // Send a reply to indicate HCI buffer is filled - EnqueueReply(m_HCIEndpoint.m_address); + EnqueueReply(m_HCIEndpoint.m_cmd_address); m_HCIEndpoint.Invalidate(); m_EventQueue.pop_front(); } @@ -434,7 +438,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e } } -u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() +u32 CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::Update() { bool packet_transferred = false; @@ -445,11 +449,11 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() const SQueuedEvent& event = m_EventQueue.front(); DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x being written from queue (%zu) to %08x...", ((hci_event_hdr_t*)event.m_buffer)->event, m_EventQueue.size() - 1, - m_HCIEndpoint.m_address); + m_HCIEndpoint.m_cmd_address); m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); m_HCIEndpoint.SetRetVal(event.m_size); // Send a reply to indicate HCI buffer is filled - EnqueueReply(m_HCIEndpoint.m_address); + EnqueueReply(m_HCIEndpoint.m_cmd_address); m_HCIEndpoint.Invalidate(); m_EventQueue.pop_front(); packet_transferred = true; @@ -507,8 +511,8 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() return packet_transferred; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u16 size, - const u16 conn_handle) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::ACLPool::Store(const u8* data, const u16 size, + const u16 conn_handle) { if (m_queue.size() >= 100) { @@ -527,7 +531,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u packet.conn_handle = conn_handle; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint) { auto& packet = m_queue.front(); @@ -537,9 +541,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& e DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from " "queue to %08x", - endpoint.m_address); + endpoint.m_cmd_address); - hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer); + hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_payload_addr); pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT); pHeader->length = size; @@ -550,11 +554,11 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& e m_queue.pop_front(); - EnqueueReply(endpoint.m_address); + EnqueueReply(endpoint.m_cmd_address); endpoint.Invalidate(); } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryComplete() +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventInquiryComplete() { SQueuedEvent Event(sizeof(SHCIEventInquiryComplete), 0); @@ -570,7 +574,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryComplete() return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryResponse() +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventInquiryResponse() { if (m_WiiMotes.empty()) return false; @@ -620,7 +624,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryResponse() return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConnectionComplete(const bdaddr_t& _bd) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventConnectionComplete(const bdaddr_t& _bd) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); if (pWiiMote == nullptr) @@ -663,7 +667,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConnectionComplete(const bdad } // This is called from Update() after ScanEnable has been enabled. -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection( +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventRequestConnection( CWII_IPC_HLE_WiiMote& _rWiiMote) { SQueuedEvent Event(sizeof(SHCIEventRequestConnection), 0); @@ -699,7 +703,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection( return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventDisconnect(u16 _connectionHandle, u8 _Reason) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventDisconnect(u16 _connectionHandle, u8 _Reason) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -723,7 +727,8 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventDisconnect(u16 _connectionHan return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventAuthenticationCompleted(u16 _connectionHandle) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventAuthenticationCompleted( + u16 _connectionHandle) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -747,7 +752,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventAuthenticationCompleted(u16 _ return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRemoteNameReq(const bdaddr_t& _bd) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventRemoteNameReq(const bdaddr_t& _bd) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); if (pWiiMote == nullptr) @@ -774,7 +779,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRemoteNameReq(const bdaddr_t& return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadRemoteFeatures(u16 _connectionHandle) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventReadRemoteFeatures(u16 _connectionHandle) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -810,7 +815,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadRemoteFeatures(u16 _conne return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadRemoteVerInfo(u16 _connectionHandle) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventReadRemoteVerInfo(u16 _connectionHandle) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -838,8 +843,8 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadRemoteVerInfo(u16 _connec return true; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandComplete(u16 opcode, const void* data, - u32 data_size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventCommandComplete(u16 opcode, const void* data, + u32 data_size) { _dbg_assert_(WII_IPC_WIIMOTE, (sizeof(SHCIEventCommand) - 2 + data_size) < 256); @@ -863,7 +868,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandComplete(u16 opcode, c AddEventToQueue(event); } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandStatus(u16 _Opcode) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventCommandStatus(u16 _Opcode) { SQueuedEvent Event(sizeof(SHCIEventStatus), 0); @@ -881,7 +886,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandStatus(u16 _Opcode) return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRoleChange(bdaddr_t _bd, bool _master) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventRoleChange(bdaddr_t _bd, bool _master) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); if (pWiiMote == nullptr) @@ -908,7 +913,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRoleChange(bdaddr_t _bd, bool return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventNumberOfCompletedPackets() +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventNumberOfCompletedPackets() { SQueuedEvent Event((u32)(sizeof(hci_event_hdr_t) + sizeof(hci_num_compl_pkts_ep) + (sizeof(hci_num_compl_pkts_info) * m_WiiMotes.size())), @@ -954,8 +959,8 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventNumberOfCompletedPackets() return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventModeChange(u16 _connectionHandle, u8 _mode, - u16 _value) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventModeChange(u16 _connectionHandle, u8 _mode, + u16 _value) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -980,7 +985,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventModeChange(u16 _connectionHan return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventLinkKeyNotification(const u8 num_to_send) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventLinkKeyNotification(const u8 num_to_send) { u8 payload_length = sizeof(hci_return_link_keys_ep) + sizeof(hci_link_key_rep_cp) * num_to_send; SQueuedEvent Event(2 + payload_length, 0); @@ -1014,7 +1019,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventLinkKeyNotification(const u8 return true; }; -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestLinkKey(const bdaddr_t& _bd) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventRequestLinkKey(const bdaddr_t& _bd) { SQueuedEvent Event(sizeof(SHCIEventRequestLinkKey), 0); @@ -1035,7 +1040,8 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestLinkKey(const bdaddr_t return true; }; -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadClockOffsetComplete(u16 _connectionHandle) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventReadClockOffsetComplete( + u16 _connectionHandle) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -1061,8 +1067,8 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadClockOffsetComplete(u16 _ return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConPacketTypeChange(u16 _connectionHandle, - u16 _packetType) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::SendEventConPacketTypeChange(u16 _connectionHandle, + u16 _packetType) { CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); if (pWiiMote == nullptr) @@ -1089,7 +1095,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConPacketTypeChange(u16 _conn // Command dispatcher // This is called from the USBV0_IOCTL_CTRLMSG Ioctlv -void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage( +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::ExecuteHCICommandMessage( const SHCICommandMessage& _rHCICommandMessage) { u8* pInput = Memory::GetPointer(_rHCICommandMessage.m_PayLoadAddr + 3); @@ -1278,7 +1284,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage( // --- command helper // // -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiry(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandInquiry(const u8* input) { // Inquiry should not be called normally const hci_inquiry_cp* inquiry = reinterpret_cast(input); @@ -1296,7 +1302,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiry(const u8* input) SendEventInquiryComplete(); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiryCancel(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandInquiryCancel(const u8* input) { hci_inquiry_cancel_rp reply; reply.status = 0x00; @@ -1306,7 +1312,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiryCancel(const u8* input) SendEventCommandComplete(HCI_CMD_INQUIRY_CANCEL, &reply, sizeof(hci_inquiry_cancel_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandCreateCon(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandCreateCon(const u8* input) { const hci_create_con_cp* create_connection = reinterpret_cast(input); @@ -1327,7 +1333,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandCreateCon(const u8* input) SendEventConnectionComplete(create_connection->bdaddr); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDisconnect(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandDisconnect(const u8* input) { const hci_discon_cp* disconnect = reinterpret_cast(input); @@ -1346,7 +1352,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDisconnect(const u8* input) wiimote->EventDisconnect(); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandAcceptCon(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandAcceptCon(const u8* input) { const hci_accept_con_cp* accept_connection = reinterpret_cast(input); @@ -1372,7 +1378,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandAcceptCon(const u8* input) SendEventConnectionComplete(accept_connection->bdaddr); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandLinkKeyRep(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandLinkKeyRep(const u8* input) { const hci_link_key_rep_cp* key_rep = reinterpret_cast(input); @@ -1389,7 +1395,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandLinkKeyRep(const u8* input) SendEventCommandComplete(HCI_CMD_LINK_KEY_REP, &reply, sizeof(hci_link_key_rep_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandLinkKeyNegRep(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandLinkKeyNegRep(const u8* input) { const hci_link_key_neg_rep_cp* key_neg = reinterpret_cast(input); @@ -1405,7 +1411,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandLinkKeyNegRep(const u8* input) SendEventCommandComplete(HCI_CMD_LINK_KEY_NEG_REP, &reply, sizeof(hci_link_key_neg_rep_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandChangeConPacketType(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandChangeConPacketType(const u8* input) { const hci_change_con_pkt_type_cp* change_packet_type = reinterpret_cast(input); @@ -1421,7 +1427,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandChangeConPacketType(const u8* i SendEventConPacketTypeChange(change_packet_type->con_handle, change_packet_type->pkt_type); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandAuthenticationRequested(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandAuthenticationRequested(const u8* input) { const hci_auth_req_cp* auth_req = reinterpret_cast(input); @@ -1432,7 +1438,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandAuthenticationRequested(const u SendEventAuthenticationCompleted(auth_req->con_handle); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandRemoteNameReq(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandRemoteNameReq(const u8* input) { const hci_remote_name_req_cp* remote_name_req = reinterpret_cast(input); @@ -1450,7 +1456,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandRemoteNameReq(const u8* input) SendEventRemoteNameReq(remote_name_req->bdaddr); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadRemoteFeatures(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadRemoteFeatures(const u8* input) { const hci_read_remote_features_cp* read_remote_features = reinterpret_cast(input); @@ -1462,7 +1468,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadRemoteFeatures(const u8* in SendEventReadRemoteFeatures(read_remote_features->con_handle); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadRemoteVerInfo(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadRemoteVerInfo(const u8* input) { const hci_read_remote_ver_info_cp* read_remote_ver_info = reinterpret_cast(input); @@ -1474,7 +1480,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadRemoteVerInfo(const u8* inp SendEventReadRemoteVerInfo(read_remote_ver_info->con_handle); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadClockOffset(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadClockOffset(const u8* input) { const hci_read_clock_offset_cp* read_clock_offset = reinterpret_cast(input); @@ -1486,7 +1492,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadClockOffset(const u8* input SendEventReadClockOffsetComplete(read_clock_offset->con_handle); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandSniffMode(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandSniffMode(const u8* input) { const hci_sniff_mode_cp* sniff_mode = reinterpret_cast(input); @@ -1501,7 +1507,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandSniffMode(const u8* input) SendEventModeChange(sniff_mode->con_handle, 0x02, sniff_mode->max_interval); // 0x02 - sniff mode } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkPolicy(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteLinkPolicy(const u8* input) { const hci_write_link_policy_settings_cp* link_policy = reinterpret_cast(input); @@ -1513,7 +1519,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkPolicy(const u8* input SendEventCommandStatus(HCI_CMD_WRITE_LINK_POLICY_SETTINGS); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReset(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReset(const u8* input) { hci_status_rp reply; reply.status = 0x00; @@ -1523,7 +1529,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReset(const u8* input) SendEventCommandComplete(HCI_CMD_RESET, &reply, sizeof(hci_status_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandSetEventFilter(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandSetEventFilter(const u8* input) { const hci_set_event_filter_cp* set_event_filter = reinterpret_cast(input); @@ -1539,7 +1545,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandSetEventFilter(const u8* input) SendEventCommandComplete(HCI_CMD_SET_EVENT_FILTER, &reply, sizeof(hci_set_event_filter_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePinType(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWritePinType(const u8* input) { const hci_write_pin_type_cp* write_pin_type = reinterpret_cast(input); @@ -1553,7 +1559,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePinType(const u8* input) SendEventCommandComplete(HCI_CMD_WRITE_PIN_TYPE, &reply, sizeof(hci_write_pin_type_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadStoredLinkKey(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadStoredLinkKey(const u8* input) { const hci_read_stored_link_key_cp* read_stored_link_key = reinterpret_cast(input); @@ -1588,7 +1594,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadStoredLinkKey(const u8* inp sizeof(hci_read_stored_link_key_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDeleteStoredLinkKey(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandDeleteStoredLinkKey(const u8* input) { const hci_delete_stored_link_key_cp* delete_stored_link_key = reinterpret_cast(input); @@ -1615,7 +1621,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDeleteStoredLinkKey(const u8* i "has failed. Could be a problem with loading the SCONF"); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLocalName(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteLocalName(const u8* input) { const hci_write_local_name_cp* write_local_name = reinterpret_cast(input); @@ -1631,7 +1637,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLocalName(const u8* input) // Here we normally receive the timeout interval. // But not from homebrew games that use lwbt. Why not? -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageTimeOut(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWritePageTimeOut(const u8* input) { const hci_write_page_timeout_cp* write_page_timeout = reinterpret_cast(input); @@ -1646,7 +1652,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageTimeOut(const u8* inpu } /* This will enable ScanEnable so that Update() can start the Wiimote. */ -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteScanEnable(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteScanEnable(const u8* input) { const hci_write_scan_enable_cp* write_scan_enable = reinterpret_cast(input); @@ -1669,7 +1675,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteScanEnable(const u8* input SendEventCommandComplete(HCI_CMD_WRITE_SCAN_ENABLE, &reply, sizeof(hci_write_scan_enable_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteUnitClass(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteUnitClass(const u8* input) { const hci_write_unit_class_cp* write_unit_class = reinterpret_cast(input); @@ -1685,7 +1691,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteUnitClass(const u8* input) SendEventCommandComplete(HCI_CMD_WRITE_UNIT_CLASS, &reply, sizeof(hci_write_unit_class_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandHostBufferSize(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandHostBufferSize(const u8* input) { const hci_host_buffer_size_cp* host_buffer_size = reinterpret_cast(input); @@ -1702,7 +1708,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandHostBufferSize(const u8* input) SendEventCommandComplete(HCI_CMD_HOST_BUFFER_SIZE, &reply, sizeof(hci_host_buffer_size_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkSupervisionTimeout(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteLinkSupervisionTimeout(const u8* input) { const hci_write_link_supervision_timeout_cp* supervision = reinterpret_cast(input); @@ -1720,7 +1726,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkSupervisionTimeout(con sizeof(hci_write_link_supervision_timeout_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryScanType(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteInquiryScanType(const u8* input) { const hci_write_inquiry_scan_type_cp* set_event_filter = reinterpret_cast(input); @@ -1735,7 +1741,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryScanType(const u8* sizeof(hci_write_inquiry_scan_type_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryMode(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWriteInquiryMode(const u8* input) { const hci_write_inquiry_mode_cp* inquiry_mode = reinterpret_cast(input); @@ -1753,7 +1759,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryMode(const u8* inpu SendEventCommandComplete(HCI_CMD_WRITE_INQUIRY_MODE, &reply, sizeof(hci_write_inquiry_mode_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageScanType(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandWritePageScanType(const u8* input) { const hci_write_page_scan_type_cp* write_page_scan_type = reinterpret_cast(input); @@ -1771,7 +1777,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageScanType(const u8* inp sizeof(hci_write_page_scan_type_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadLocalVer(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadLocalVer(const u8* input) { hci_read_local_ver_rp reply; reply.status = 0x00; @@ -1792,7 +1798,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadLocalVer(const u8* input) SendEventCommandComplete(HCI_CMD_READ_LOCAL_VER, &reply, sizeof(hci_read_local_ver_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadLocalFeatures(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadLocalFeatures(const u8* input) { hci_read_local_features_rp reply; reply.status = 0x00; @@ -1814,7 +1820,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadLocalFeatures(const u8* inp SendEventCommandComplete(HCI_CMD_READ_LOCAL_FEATURES, &reply, sizeof(hci_read_local_features_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBufferSize(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadBufferSize(const u8* input) { hci_read_buffer_size_rp reply; reply.status = 0x00; @@ -1836,7 +1842,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBufferSize(const u8* input) SendEventCommandComplete(HCI_CMD_READ_BUFFER_SIZE, &reply, sizeof(hci_read_buffer_size_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBDAdrr(const u8* input) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadBDAdrr(const u8* input) { hci_read_bdaddr_rp reply; reply.status = 0x00; @@ -1851,7 +1857,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBDAdrr(const u8* input) SendEventCommandComplete(HCI_CMD_READ_BDADDR, &reply, sizeof(hci_read_bdaddr_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4F(const u8* input, u32 size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandVendorSpecific_FC4F(const u8* input, u32 size) { // callstack... // BTM_VendorSpecificCommad() @@ -1871,7 +1877,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4F(const u8* i SendEventCommandComplete(0xFC4F, &reply, sizeof(hci_status_rp)); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4C(const u8* input, u32 size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandVendorSpecific_FC4C(const u8* input, u32 size) { hci_status_rp reply; reply.status = 0x00; @@ -1888,7 +1894,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4C(const u8* i // --- helper // // -CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(const bdaddr_t& _rAddr) +CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::AccessWiiMote(const bdaddr_t& _rAddr) { for (auto& wiimote : m_WiiMotes) { @@ -1903,7 +1909,7 @@ CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(const b return nullptr; } -CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(u16 _ConnectionHandle) +CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::AccessWiiMote(u16 _ConnectionHandle) { for (auto& wiimote : m_WiiMotes) { @@ -1916,8 +1922,8 @@ CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(u16 _Co return nullptr; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::DisplayDisconnectMessage(const int wiimoteNumber, - const int reason) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::DisplayDisconnectMessage(const int wiimoteNumber, + const int reason) { // TODO: If someone wants to be fancy we could also figure out what the values for pDiscon->reason // mean @@ -1926,7 +1932,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DisplayDisconnectMessage(const int wii StringFromFormat("Wiimote %i disconnected by emulated software", wiimoteNumber), 3000); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::LOG_LinkKey(const u8* _pLinkKey) +void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::LOG_LinkKey(const u8* _pLinkKey) { DEBUG_LOG(WII_IPC_WIIMOTE, " link key: " "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h similarity index 81% rename from Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h rename to Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h index 3cdda8d61f..bdf5404d74 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h @@ -12,6 +12,7 @@ #include "Core/HW/Wiimote.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" #include "Core/IPC_HLE/hci.h" class CWII_IPC_HLE_WiiMote; @@ -19,8 +20,8 @@ class CWII_IPC_HLE_WiiMote; struct SQueuedEvent { u8 m_buffer[1024]; - u32 m_size; - u16 m_connectionHandle; + u32 m_size = 0; + u16 m_connectionHandle = 0; SQueuedEvent(u32 size, u16 connectionHandle) : m_size(size), m_connectionHandle(connectionHandle) { @@ -32,19 +33,20 @@ struct SQueuedEvent memset(m_buffer, 0, 1024); } - SQueuedEvent() : m_size(0), m_connectionHandle(0) {} + SQueuedEvent() = default; }; // Important to remember that this class is for /dev/usb/oh1/57e/305 ONLY // /dev/usb/oh1 -> internal usb bus // 57e/305 -> VendorID/ProductID of device on usb bus // This device is ONLY the internal Bluetooth module (based on BCM2045 chip) -class CWII_IPC_HLE_Device_usb_oh1_57e_305 : public IWII_IPC_HLE_Device +class CWII_IPC_HLE_Device_usb_oh1_57e_305_emu final + : public CWII_IPC_HLE_Device_usb_oh1_57e_305_base { public: - CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName); + CWII_IPC_HLE_Device_usb_oh1_57e_305_emu(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_usb_oh1_57e_305(); + virtual ~CWII_IPC_HLE_Device_usb_oh1_57e_305_emu(); IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; @@ -61,8 +63,6 @@ public: bool RemoteDisconnect(u16 _connectionHandle); - // hack for Wiimote plugin -public: std::vector m_WiiMotes; CWII_IPC_HLE_WiiMote* AccessWiiMote(const bdaddr_t& _rAddr); CWII_IPC_HLE_WiiMote* AccessWiiMote(u16 _ConnectionHandle); @@ -70,21 +70,6 @@ public: void DoState(PointerWrap& p) override; private: - enum USBIOCtl - { - USBV0_IOCTL_CTRLMSG = 0, - USBV0_IOCTL_BLKMSG = 1, - USBV0_IOCTL_INTRMSG = 2, - }; - - enum USBEndpoint - { - HCI_CTRL = 0x00, - HCI_EVENT = 0x81, - ACL_DATA_IN = 0x82, - ACL_DATA_OUT = 0x02 - }; - struct SHCICommandMessage { u8 bRequestType; @@ -98,36 +83,10 @@ private: u32 m_Address; }; - // This is a lightweight/specialized version of SIOCtlVBuffer - struct CtrlBuffer - { - u32 m_address; - u32 m_buffer; - - CtrlBuffer(u32 _Address) : m_address(_Address), m_buffer() - { - if (m_address) - { - u32 InBufferNum = Memory::Read_U32(m_address + 0x10); - u32 BufferVector = Memory::Read_U32(m_address + 0x18); - m_buffer = Memory::Read_U32(BufferVector + InBufferNum * sizeof(SIOCtlVBuffer::SBuffer)); - } - } - - inline void FillBuffer(const void* src, const size_t size) const - { - Memory::CopyToEmu(m_buffer, (u8*)src, size); - } - - inline void SetRetVal(const u32 retval) const { Memory::Write_U32(retval, m_address + 4); } - inline bool IsValid() const { return m_address != 0; } - inline void Invalidate() { m_address = m_buffer = 0; } - }; - bdaddr_t m_ControllerBD; // this is used to trigger connecting via ACL - u8 m_ScanEnable; + u8 m_ScanEnable = 0; SHCICommandMessage m_CtrlSetup; CtrlBuffer m_HCIEndpoint; @@ -162,7 +121,7 @@ private: } m_acl_pool; u32 m_PacketCount[MAX_BBMOTES]; - u64 m_last_ticks; + u64 m_last_ticks = 0; // Send ACL data to a device (wiimote) void IncDataPacket(u16 _ConnectionHandle); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp new file mode 100644 index 0000000000..ff5dcf0af4 --- /dev/null +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp @@ -0,0 +1,370 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include + +#include "Common/Network.h" +#include "Common/Thread.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/CoreTiming.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h" +#include "Core/IPC_HLE/hci.h" + +// This flag is set when a libusb transfer failed (for reasons other than timing out) +// and we showed an OSD message about it. +static Common::Flag s_showed_failed_transfer; + +static void EnqueueReply(const u32 command_address) +{ + Memory::Write_U32(Memory::Read_U32(command_address), command_address + 8); + Memory::Write_U32(IPC_REP_ASYNC, command_address); + WII_IPC_HLE_Interface::EnqueueReply(command_address, 0, CoreTiming::FromThread::ANY); +} + +static bool IsWantedDevice(libusb_device_descriptor& descriptor) +{ + const int vid = SConfig::GetInstance().m_bt_passthrough_vid; + const int pid = SConfig::GetInstance().m_bt_passthrough_pid; + if (vid == -1 || pid == -1) + return true; + return descriptor.idVendor == vid && descriptor.idProduct == pid; +} + +CWII_IPC_HLE_Device_usb_oh1_57e_305_real::CWII_IPC_HLE_Device_usb_oh1_57e_305_real( + u32 device_id, const std::string& device_name) + : CWII_IPC_HLE_Device_usb_oh1_57e_305_base(device_id, device_name) +{ + const int ret = libusb_init(&m_libusb_context); + _assert_msg_(WII_IPC_WIIMOTE, ret == 0, "Failed to init libusb."); +} + +CWII_IPC_HLE_Device_usb_oh1_57e_305_real::~CWII_IPC_HLE_Device_usb_oh1_57e_305_real() +{ + if (m_handle != nullptr) + { + SendHCIResetCommand(); + libusb_release_interface(m_handle, 0); + // libusb_handle_events() may block the libusb thread indefinitely, so we need to + // call libusb_close() first then immediately stop the thread in StopTransferThread. + StopTransferThread(); + libusb_unref_device(m_device); + } + + libusb_exit(m_libusb_context); +} + +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::Open(u32 command_address, u32 mode) +{ + libusb_device** list; + const ssize_t cnt = libusb_get_device_list(m_libusb_context, &list); + _dbg_assert_msg_(WII_IPC_HLE, cnt > 0, "Couldn't get device list"); + for (ssize_t i = 0; i < cnt; ++i) + { + libusb_device* device = list[i]; + libusb_device_descriptor device_descriptor; + libusb_config_descriptor* config_descriptor; + libusb_get_device_descriptor(device, &device_descriptor); + const int ret = libusb_get_active_config_descriptor(device, &config_descriptor); + if (ret != 0) + { + ERROR_LOG(WII_IPC_WIIMOTE, "Failed to get config descriptor for device %04x:%04x: %s", + device_descriptor.idVendor, device_descriptor.idProduct, libusb_error_name(ret)); + continue; + } + + const libusb_interface& interface = config_descriptor->interface[INTERFACE]; + const libusb_interface_descriptor& descriptor = interface.altsetting[0]; + if (descriptor.bInterfaceClass == LIBUSB_CLASS_WIRELESS && + descriptor.bInterfaceSubClass == SUBCLASS && + descriptor.bInterfaceProtocol == PROTOCOL_BLUETOOTH && IsWantedDevice(device_descriptor) && + OpenDevice(device)) + { + unsigned char manufacturer[50] = {}, product[50] = {}, serial_number[50] = {}; + libusb_get_string_descriptor_ascii(m_handle, device_descriptor.iManufacturer, manufacturer, + sizeof(manufacturer)); + libusb_get_string_descriptor_ascii(m_handle, device_descriptor.iProduct, product, + sizeof(product)); + libusb_get_string_descriptor_ascii(m_handle, device_descriptor.iSerialNumber, serial_number, + sizeof(serial_number)); + NOTICE_LOG(WII_IPC_WIIMOTE, "Using device %04x:%04x (rev %x) for Bluetooth: %s %s %s", + device_descriptor.idVendor, device_descriptor.idProduct, + device_descriptor.bcdDevice, manufacturer, product, serial_number); + libusb_free_config_descriptor(config_descriptor); + break; + } + libusb_free_config_descriptor(config_descriptor); + } + libusb_free_device_list(list, 1); + + if (m_handle == nullptr) + { + PanicAlertT("Bluetooth passthrough mode is enabled, " + "but no usable Bluetooth USB device was found. Aborting."); + Core::QueueHostJob(Core::Stop); + return GetNoReply(); + } + + StartTransferThread(); + + Memory::Write_U32(GetDeviceID(), command_address + 4); + m_Active = true; + return GetDefaultReply(); +} + +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::Close(u32 command_address, bool force) +{ + if (!force) + { + libusb_release_interface(m_handle, 0); + StopTransferThread(); + libusb_unref_device(m_device); + m_handle = nullptr; + Memory::Write_U32(0, command_address + 4); + } + + m_Active = false; + return GetDefaultReply(); +} + +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_address) +{ + const SIOCtlVBuffer cmd_buffer(command_address); + switch (cmd_buffer.Parameter) + { + // HCI commands to the Bluetooth adapter + case USBV0_IOCTL_CTRLMSG: + { + auto cmd = std::make_unique(cmd_buffer); + auto buffer = std::vector(cmd->length + LIBUSB_CONTROL_SETUP_SIZE); + libusb_fill_control_setup(buffer.data(), cmd->request_type, cmd->request, cmd->value, + cmd->index, cmd->length); + Memory::CopyFromEmu(buffer.data() + LIBUSB_CONTROL_SETUP_SIZE, cmd->payload_addr, cmd->length); + libusb_transfer* transfer = libusb_alloc_transfer(0); + transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_fill_control_transfer(transfer, m_handle, buffer.data(), CommandCallback, cmd.release(), + 0); + libusb_submit_transfer(transfer); + break; + } + // ACL data (incoming or outgoing) and incoming HCI events (respectively) + case USBV0_IOCTL_BLKMSG: + case USBV0_IOCTL_INTRMSG: + { + auto buffer = std::make_unique(cmd_buffer, command_address); + if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && + m_sync_button_state == SyncButtonState::Pressed) + { + Core::DisplayMessage("Scanning for Wiimotes", 2000); + FakeSyncButtonPressedEvent(*buffer); + return GetNoReply(); + } + if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && + m_sync_button_state == SyncButtonState::LongPressed) + { + Core::DisplayMessage("Reset saved Wiimote pairings", 2000); + FakeSyncButtonHeldEvent(*buffer); + return GetNoReply(); + } + libusb_transfer* transfer = libusb_alloc_transfer(0); + transfer->buffer = Memory::GetPointer(buffer->m_payload_addr); + transfer->callback = TransferCallback; + transfer->dev_handle = m_handle; + transfer->endpoint = buffer->m_endpoint; + transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + transfer->length = buffer->m_length; + transfer->timeout = TIMEOUT; + transfer->type = cmd_buffer.Parameter == USBV0_IOCTL_BLKMSG ? LIBUSB_TRANSFER_TYPE_BULK : + LIBUSB_TRANSFER_TYPE_INTERRUPT; + transfer->user_data = buffer.release(); + libusb_submit_transfer(transfer); + break; + } + } + // Replies are generated inside of the message handlers (and asynchronously). + return GetNoReply(); +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::DoState(PointerWrap& p) +{ + bool passthrough_bluetooth = true; + p.Do(passthrough_bluetooth); + if (p.GetMode() == PointerWrap::MODE_READ) + PanicAlertT("Attempted to load a state. Bluetooth will likely be broken now."); + + if (!passthrough_bluetooth && p.GetMode() == PointerWrap::MODE_READ) + { + Core::DisplayMessage("State needs Bluetooth passthrough to be disabled. Aborting load.", 4000); + p.SetMode(PointerWrap::MODE_VERIFY); + } +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::UpdateSyncButtonState(const bool is_held) +{ + if (m_sync_button_state == SyncButtonState::Unpressed && is_held) + { + m_sync_button_held_timer.Update(); + m_sync_button_state = SyncButtonState::Held; + } + + if (m_sync_button_state == SyncButtonState::Held && is_held && + m_sync_button_held_timer.GetTimeDifference() > SYNC_BUTTON_HOLD_MS_TO_RESET) + m_sync_button_state = SyncButtonState::LongPressed; + else if (m_sync_button_state == SyncButtonState::Held && !is_held) + m_sync_button_state = SyncButtonState::Pressed; + + if (m_sync_button_state == SyncButtonState::Ignored && !is_held) + m_sync_button_state = SyncButtonState::Unpressed; +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TriggerSyncButtonPressedEvent() +{ + m_sync_button_state = SyncButtonState::Pressed; +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TriggerSyncButtonHeldEvent() +{ + m_sync_button_state = SyncButtonState::LongPressed; +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIResetCommand() +{ + const u8 type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE; + u8 packet[3] = {}; + const u16 payload[] = {HCI_CMD_RESET}; + memcpy(packet, payload, sizeof(payload)); + libusb_control_transfer(m_handle, type, 0, 0, 0, packet, sizeof(packet), TIMEOUT); + INFO_LOG(WII_IPC_WIIMOTE, "Sent a reset command to adapter"); +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeSyncButtonEvent(const CtrlBuffer& ctrl, + const u8* payload, const u8 size) +{ + u8* packet = Memory::GetPointer(ctrl.m_payload_addr); + auto* hci_event = reinterpret_cast(packet); + hci_event->event = HCI_EVENT_VENDOR; + hci_event->length = size; + memcpy(packet + sizeof(hci_event_hdr_t), payload, size); + ctrl.SetRetVal(sizeof(hci_event_hdr_t) + size); + EnqueueReply(ctrl.m_cmd_address); +} + +// When the red sync button is pressed, a HCI event is generated: +// > HCI Event: Vendor (0xff) plen 1 +// 08 +// This causes the emulated software to perform a BT inquiry and connect to found Wiimotes. +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeSyncButtonPressedEvent(const CtrlBuffer& ctrl) +{ + NOTICE_LOG(WII_IPC_WIIMOTE, "Faking 'sync button pressed' (0x08) event packet"); + const u8 payload[1] = {0x08}; + FakeSyncButtonEvent(ctrl, payload, sizeof(payload)); + m_sync_button_state = SyncButtonState::Ignored; +} + +// When the red sync button is held for 10 seconds, a HCI event with payload 09 is sent. +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeSyncButtonHeldEvent(const CtrlBuffer& ctrl) +{ + NOTICE_LOG(WII_IPC_WIIMOTE, "Faking 'sync button held' (0x09) event packet"); + const u8 payload[1] = {0x09}; + FakeSyncButtonEvent(ctrl, payload, sizeof(payload)); + m_sync_button_state = SyncButtonState::Ignored; +} + +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_real::OpenDevice(libusb_device* device) +{ + m_device = libusb_ref_device(device); + const int ret = libusb_open(m_device, &m_handle); + if (ret != 0) + { + PanicAlertT("Failed to open Bluetooth device: %s", libusb_error_name(ret)); + return false; + } + + const int result = libusb_detach_kernel_driver(m_handle, INTERFACE); + if (result < 0 && result != LIBUSB_ERROR_NOT_FOUND && result != LIBUSB_ERROR_NOT_SUPPORTED) + { + PanicAlertT("Failed to detach kernel driver for BT passthrough: %s", libusb_error_name(result)); + return false; + } + if (libusb_claim_interface(m_handle, INTERFACE) < 0) + { + PanicAlertT("Failed to claim interface for BT passthrough"); + return false; + } + + return true; +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::StartTransferThread() +{ + if (m_thread_running.IsSet()) + return; + m_thread_running.Set(); + m_thread = std::thread(&CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TransferThread, this); +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::StopTransferThread() +{ + if (m_thread_running.TestAndClear()) + { + libusb_close(m_handle); + m_thread.join(); + } +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TransferThread() +{ + Common::SetCurrentThreadName("BT USB Thread"); + while (m_thread_running.IsSet()) + { + libusb_handle_events_completed(m_libusb_context, nullptr); + } +} + +// The callbacks are called from libusb code on a separate thread. +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::CommandCallback(libusb_transfer* tr) +{ + const std::unique_ptr cmd(static_cast(tr->user_data)); + if (tr->status != LIBUSB_TRANSFER_COMPLETED && tr->status != LIBUSB_TRANSFER_NO_DEVICE) + { + ERROR_LOG(WII_IPC_WIIMOTE, "libusb command transfer failed, status: 0x%02x", tr->status); + if (!s_showed_failed_transfer.IsSet()) + { + Core::DisplayMessage("Failed to send a command to the Bluetooth adapter.", 10000); + Core::DisplayMessage("It may not be compatible with passthrough mode.", 10000); + s_showed_failed_transfer.Set(); + } + } + else + { + s_showed_failed_transfer.Clear(); + } + + EnqueueReply(cmd->address); +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TransferCallback(libusb_transfer* tr) +{ + const std::unique_ptr ctrl(static_cast(tr->user_data)); + if (tr->status != LIBUSB_TRANSFER_COMPLETED && tr->status != LIBUSB_TRANSFER_TIMED_OUT && + tr->status != LIBUSB_TRANSFER_NO_DEVICE) + { + ERROR_LOG(WII_IPC_WIIMOTE, "libusb transfer failed, status: 0x%02x", tr->status); + if (!s_showed_failed_transfer.IsSet()) + { + Core::DisplayMessage("Failed to transfer to or from to the Bluetooth adapter.", 10000); + Core::DisplayMessage("It may not be compatible with passthrough mode.", 10000); + s_showed_failed_transfer.Set(); + } + } + else + { + s_showed_failed_transfer.Clear(); + } + ctrl->SetRetVal(tr->actual_length); + EnqueueReply(ctrl->m_cmd_address); +} diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h new file mode 100644 index 0000000000..87a005a2be --- /dev/null +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h @@ -0,0 +1,83 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#if defined(__LIBUSB__) +#include +#include + +#include "Common/Flag.h" +#include "Common/Timer.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" + +struct libusb_device; +struct libusb_device_handle; +struct libusb_context; +struct libusb_transfer; + +enum class SyncButtonState +{ + Unpressed, + Held, + Pressed, + LongPressed, + // On a real Wii, after a long press, the button release is ignored and doesn't trigger a sync. + Ignored, +}; + +class CWII_IPC_HLE_Device_usb_oh1_57e_305_real final + : public CWII_IPC_HLE_Device_usb_oh1_57e_305_base +{ +public: + CWII_IPC_HLE_Device_usb_oh1_57e_305_real(u32 device_id, const std::string& device_name); + ~CWII_IPC_HLE_Device_usb_oh1_57e_305_real() override; + + IPCCommandResult Open(u32 command_address, u32 mode) override; + IPCCommandResult Close(u32 command_address, bool force) override; + IPCCommandResult IOCtlV(u32 command_address) override; + + void DoState(PointerWrap& p) override; + u32 Update() override { return 0; } + void UpdateSyncButtonState(bool is_held) override; + void TriggerSyncButtonPressedEvent() override; + void TriggerSyncButtonHeldEvent() override; + +private: + static constexpr u8 INTERFACE = 0x00; + static constexpr u8 SUBCLASS = 0x01; + static constexpr u8 PROTOCOL_BLUETOOTH = 0x01; + // Arbitrarily chosen value that allows emulated software to send commands often enough + // so that the sync button event is triggered at least every 200ms. + // Ideally this should be equal to 0, so we don't trigger unnecessary libusb transfers. + static constexpr int TIMEOUT = 200; + static constexpr int SYNC_BUTTON_HOLD_MS_TO_RESET = 10000; + + std::atomic m_sync_button_state{SyncButtonState::Unpressed}; + Common::Timer m_sync_button_held_timer; + + libusb_device* m_device = nullptr; + libusb_device_handle* m_handle = nullptr; + libusb_context* m_libusb_context = nullptr; + + Common::Flag m_thread_running; + std::thread m_thread; + + void SendHCIResetCommand(); + void FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, u8 size); + void FakeSyncButtonPressedEvent(const CtrlBuffer& ctrl); + void FakeSyncButtonHeldEvent(const CtrlBuffer& ctrl); + + bool OpenDevice(libusb_device* device); + void StartTransferThread(); + void StopTransferThread(); + void TransferThread(); + static void CommandCallback(libusb_transfer* transfer); + static void TransferCallback(libusb_transfer* transfer); +}; + +#else +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h" +using CWII_IPC_HLE_Device_usb_oh1_57e_305_real = CWII_IPC_HLE_Device_usb_oh1_57e_305_stub; +#endif diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.cpp new file mode 100644 index 0000000000..1677699fe6 --- /dev/null +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.cpp @@ -0,0 +1,24 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h" +#include "Common/MsgHandler.h" + +namespace Core +{ +void DisplayMessage(const std::string& message, int time_in_ms); +} + +IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_stub::Open(u32 command_address, u32 mode) +{ + PanicAlertT("Bluetooth passthrough mode is enabled, but Dolphin was built without libusb." + " Passthrough mode cannot be used."); + return GetNoReply(); +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_stub::DoState(PointerWrap& p) +{ + Core::DisplayMessage("The current IPC_HLE_Device_usb is a stub. Aborting load.", 4000); + p.SetMode(PointerWrap::MODE_VERIFY); +} diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h new file mode 100644 index 0000000000..2e0ed16691 --- /dev/null +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_stub.h @@ -0,0 +1,24 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" + +class CWII_IPC_HLE_Device_usb_oh1_57e_305_stub final + : public CWII_IPC_HLE_Device_usb_oh1_57e_305_base +{ +public: + CWII_IPC_HLE_Device_usb_oh1_57e_305_stub(u32 device_id, const std::string& device_name) + : CWII_IPC_HLE_Device_usb_oh1_57e_305_base(device_id, device_name) + { + } + ~CWII_IPC_HLE_Device_usb_oh1_57e_305_stub() override {} + IPCCommandResult Open(u32 command_address, u32 mode) override; + IPCCommandResult Close(u32 command_address, bool force) override { return GetNoReply(); } + IPCCommandResult IOCtl(u32 command_address) override { return GetDefaultReply(); } + IPCCommandResult IOCtlV(u32 command_address) override { return GetNoReply(); } + void DoState(PointerWrap& p) override; + u32 Update() override { return 0; } +}; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp index 1ae285fc44..847aa21060 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp @@ -6,7 +6,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" // Local core functions -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h" #ifdef _WIN32 diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp index 563deb4eb3..d48d6abb6a 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp @@ -10,25 +10,25 @@ #include "Core/Core.h" #include "Core/HW/Wiimote.h" #include "Core/Host.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/IPC_HLE/WiiMote_HID_Attr.h" #include "Core/IPC_HLE/l2cap.h" -static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = nullptr; +static CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* s_Usb = nullptr; -CWII_IPC_HLE_Device_usb_oh1_57e_305* GetUsbPointer() +CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* GetUsbPointer() { return s_Usb; } -void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305* ptr) +void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* ptr) { s_Usb = ptr; } -CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, - bdaddr_t _BD, bool ready) +CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* _pHost, + int _Number, bdaddr_t _BD, bool ready) : m_HIDControlChannel_Connected(false), m_HIDControlChannel_ConnectedWait(false), m_HIDControlChannel_Config(false), m_HIDControlChannel_ConfigWait(false), m_HIDInterruptChannel_Connected(false), m_HIDInterruptChannel_ConnectedWait(false), @@ -71,6 +71,16 @@ CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* void CWII_IPC_HLE_WiiMote::DoState(PointerWrap& p) { + bool passthrough_bluetooth = false; + p.Do(passthrough_bluetooth); + if (passthrough_bluetooth && p.GetMode() == PointerWrap::MODE_READ) + { + Core::DisplayMessage("State needs Bluetooth passthrough to be enabled. Aborting load state.", + 3000); + p.SetMode(PointerWrap::MODE_VERIFY); + return; + } + // this function is usually not called... see CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState p.Do(m_ConnectionState); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h index b9cf483234..fdb2b02cb9 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h @@ -11,11 +11,11 @@ #include "Common/CommonTypes.h" #include "Core/IPC_HLE/hci.h" -class CWII_IPC_HLE_Device_usb_oh1_57e_305; +class CWII_IPC_HLE_Device_usb_oh1_57e_305_emu; class PointerWrap; -CWII_IPC_HLE_Device_usb_oh1_57e_305* GetUsbPointer(); -void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305* ptr); +CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* GetUsbPointer(); +void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* ptr); class CBigEndianBuffer { @@ -35,7 +35,7 @@ private: class CWII_IPC_HLE_WiiMote { public: - CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, bdaddr_t _BD, + CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* _pHost, int _Number, bdaddr_t _BD, bool ready = false); virtual ~CWII_IPC_HLE_WiiMote() {} @@ -93,7 +93,7 @@ private: u16 lmp_subversion; u8 m_LinkKey[HCI_KEY_SIZE]; std::string m_Name; - CWII_IPC_HLE_Device_usb_oh1_57e_305* m_pHost; + CWII_IPC_HLE_Device_usb_oh1_57e_305_emu* m_pHost; struct SChannel { diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 6bd3f72f0a..702fe58e54 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -29,7 +29,7 @@ #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" @@ -570,7 +570,8 @@ void ChangeWiiPads(bool instantly) for (int i = 0; i < MAX_WIIMOTES; ++i) { g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE; - GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); + if (!SConfig::GetInstance().m_bt_passthrough_enabled) + GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); } } diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 6180b3e13d..30c7e56424 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -22,7 +22,7 @@ #include "Core/HW/Sram.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/Movie.h" #include "InputCommon/GCAdapter.h" #include "VideoCommon/OnScreenDisplay.h" diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 89bd1d7211..c1efa7d2d9 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 61; // Last changed in PR 4216 +static const u32 STATE_VERSION = 62; // Last changed in PR 4195 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index 92e0e79c5b..e05250f3d8 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -60,6 +60,7 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent) SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); SetSizerAndFit(main_sizer); Center(); + UpdateUI(); } wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() @@ -141,9 +142,6 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() { - wxStaticText* wiimote_label[4]; - wxChoice* wiimote_source_ch[4]; - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) { wxString wiimote_str = wxString::Format(_("Wiimote %i"), i + 1); @@ -160,10 +158,10 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() int config_bt_id = wxWindow::NewControlId(); m_wiimote_index_from_config_id.emplace(config_bt_id, i); - wiimote_label[i] = new wxStaticText(this, wxID_ANY, wiimote_str); - wiimote_source_ch[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, + m_wiimote_labels[i] = new wxStaticText(this, wxID_ANY, wiimote_str); + m_wiimote_sources[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, src_choices.size(), src_choices.data()); - wiimote_source_ch[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this); + m_wiimote_sources[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this); m_wiimote_configure_button[i] = new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(80, 25)); m_wiimote_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteConfigButton, @@ -173,9 +171,9 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() bool wii_game_started = SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED; if (Core::g_want_determinism || !wii_game_started) - wiimote_source_ch[i]->Disable(); + m_wiimote_sources[i]->Disable(); - wiimote_source_ch[i]->Select(g_wiimote_sources[i]); + m_wiimote_sources[i]->Select(g_wiimote_sources[i]); if (!wii_game_started || (g_wiimote_sources[i] != WIIMOTE_SRC_EMU && g_wiimote_sources[i] != WIIMOTE_SRC_HYBRID)) m_wiimote_configure_button[i]->Disable(); @@ -187,8 +185,8 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() wxFlexGridSizer* const wiimote_sizer = new wxFlexGridSizer(3, 5, 5); for (unsigned int i = 0; i < 4; ++i) { - wiimote_sizer->Add(wiimote_label[i], 0, wxALIGN_CENTER_VERTICAL); - wiimote_sizer->Add(wiimote_source_ch[i], 0, wxALIGN_CENTER_VERTICAL); + wiimote_sizer->Add(m_wiimote_labels[i], 0, wxALIGN_CENTER_VERTICAL); + wiimote_sizer->Add(m_wiimote_sources[i], 0, wxALIGN_CENTER_VERTICAL); wiimote_sizer->Add(m_wiimote_configure_button[i]); } wiimote_control_section->Add(wiimote_sizer, 1, wxEXPAND, 5); @@ -198,8 +196,8 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() { for (int i = 0; i < 4; ++i) { - wiimote_label[i]->Disable(); - wiimote_source_ch[i]->Disable(); + m_wiimote_labels[i]->Disable(); + m_wiimote_sources[i]->Disable(); } } @@ -209,15 +207,15 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() wiimote_group->AddSpacer(5); wiimote_group->Add(CreateRealWiimoteSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); wiimote_group->AddSpacer(5); - wiimote_group->Add(CreateGeneralWiimoteSettingsSizer(), 0, - wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); + m_general_wm_settings = CreateGeneralWiimoteSettingsSizer(); + wiimote_group->Add(m_general_wm_settings, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); return wiimote_group; } wxStaticBoxSizer* ControllerConfigDiag::CreateBalanceBoardSizer() { - wxStaticBoxSizer* const bb_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Balance Board")); + m_balance_board_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Balance Board")); wxFlexGridSizer* const bb_sizer = new wxFlexGridSizer(1, 5, 5); int source_ctrl_id = wxWindow::NewControlId(); @@ -233,40 +231,74 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateBalanceBoardSizer() bb_sizer->Add(bb_source, 0, wxALIGN_CENTER_VERTICAL); - bb_group->Add(bb_sizer, 1, wxEXPAND, 5); + m_balance_board_group->Add(bb_sizer, 1, wxEXPAND, 5); // Disable when emulation is running. if (Core::GetState() != Core::CORE_UNINITIALIZED) bb_source->Disable(); - return bb_group; + return m_balance_board_group; } wxStaticBoxSizer* ControllerConfigDiag::CreateRealWiimoteSizer() { - // "Real wiimotes" controls - wxButton* const refresh_btn = new wxButton(this, wxID_ANY, _("Refresh")); - refresh_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this); + auto* const real_wiimotes_group = new wxStaticBoxSizer(wxVERTICAL, this, _("Real Wiimotes")); - wxStaticBoxSizer* const real_wiimotes_group = - new wxStaticBoxSizer(wxVERTICAL, this, _("Real Wiimotes")); - wxBoxSizer* const real_wiimotes_sizer = new wxBoxSizer(wxHORIZONTAL); + m_unsupported_bt_text = + new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found.\n" + "You must manually connect your Wiimotes.")); + real_wiimotes_group->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxALL, 5); + m_unsupported_bt_text->Show(!WiimoteReal::g_wiimote_scanner.IsReady()); - if (!WiimoteReal::g_wiimote_scanner.IsReady()) - real_wiimotes_group->Add( - new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found.\n" - "You must manually connect your Wiimotes.")), - 0, wxALIGN_CENTER | wxALL, 5); + // Bluetooth adapter passthrough + m_bt_passthrough_text = new wxStaticText( + this, wxID_ANY, _("A Bluetooth adapter will be passed through to the game.\n" + "Only real Wiimotes will be usable.\n" + "Wiimotes can be synced to Dolphin with the sync hotkey.")); + real_wiimotes_group->Add(m_bt_passthrough_text, 0, wxALIGN_CENTER | wxALL, 5); - wxCheckBox* const continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning")); + auto* const enable_passthrough = + new wxCheckBox(this, wxID_ANY, _("Enable Bluetooth Adapter Passthrough")); + enable_passthrough->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnPassthroughMode, this); + enable_passthrough->SetValue(SConfig::GetInstance().m_bt_passthrough_enabled); + + auto* const wm_bt_sync_button = new wxButton(this, wxID_ANY, _("Sync Wiimotes")); + wm_bt_sync_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughScanButton, this); + auto* const wm_bt_reset_button = new wxButton(this, wxID_ANY, _("Reset pairings")); + wm_bt_reset_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton, this); + + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + enable_passthrough->Disable(); + if (!SConfig::GetInstance().bWii) + m_bt_passthrough_text->Disable(); + } + + if (!SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED) + { + wm_bt_sync_button->Disable(); + wm_bt_reset_button->Disable(); + } + + m_bt_passthrough_sizer = new wxBoxSizer(wxHORIZONTAL); + m_bt_passthrough_sizer->Add(wm_bt_sync_button, 0, wxALIGN_CENTER_VERTICAL); + m_bt_passthrough_sizer->Add(wm_bt_reset_button, 0, wxALL | wxALIGN_CENTER, 5); + + // Regular real Wiimotes controls + auto* const continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning")); continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning, this); continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning); + auto* const wm_refresh_button = new wxButton(this, wxID_ANY, _("Refresh")); + wm_refresh_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this); - real_wiimotes_sizer->Add(continuous_scanning, 0, wxALIGN_CENTER_VERTICAL); - real_wiimotes_sizer->AddStretchSpacer(); - real_wiimotes_sizer->Add(refresh_btn, 0, wxALL | wxALIGN_CENTER, 5); + m_real_wiimotes_sizer = new wxBoxSizer(wxHORIZONTAL); + m_real_wiimotes_sizer->Add(continuous_scanning, 0, wxALIGN_CENTER_VERTICAL); + m_real_wiimotes_sizer->AddStretchSpacer(); + m_real_wiimotes_sizer->Add(wm_refresh_button, 0, wxALL | wxALIGN_CENTER, 5); - real_wiimotes_group->Add(real_wiimotes_sizer, 0, wxEXPAND); + real_wiimotes_group->Add(enable_passthrough, 0); + real_wiimotes_group->Add(m_bt_passthrough_sizer, 0, wxEXPAND); + real_wiimotes_group->Add(m_real_wiimotes_sizer, 0, wxEXPAND); return real_wiimotes_group; } @@ -280,9 +312,9 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGeneralWiimoteSettingsSizer() wxSlider* const WiimoteSpkVolume = new wxSlider(this, wxID_ANY, 0, 0, 127); wxCheckBox* const WiimoteMotor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor")); - auto wiimote_speaker = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data")); - wiimote_speaker->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this); - wiimote_speaker->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker); + m_enable_speaker_data = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data")); + m_enable_speaker_data->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this); + m_enable_speaker_data->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker); wxStaticText* const WiiSensBarPosText = new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")); @@ -348,7 +380,7 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGeneralWiimoteSettingsSizer() wxGridSizer* const general_wiimote_sizer = new wxGridSizer(1, 5, 5); general_wiimote_sizer->Add(WiimoteMotor); - general_wiimote_sizer->Add(wiimote_speaker); + general_wiimote_sizer->Add(m_enable_speaker_data); general_sizer->Add(choice_sizer); general_sizer->Add(general_wiimote_sizer); diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index 18c1496b52..f8b4ef3a2c 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -6,16 +6,22 @@ #include #include +#include +#include +#include #include +#include +#include +#include #include "Common/SysConf.h" #include "Core/ConfigManager.h" #include "Core/HW/Wiimote.h" +#include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h" #include "InputCommon/GCAdapter.h" class InputConfig; -class wxButton; -class wxStaticBoxSizer; class ControllerConfigDiag : public wxDialog { @@ -54,12 +60,55 @@ private: event.Skip(); } + void OnPassthroughMode(wxCommandEvent& event) + { + SConfig::GetInstance().m_bt_passthrough_enabled = event.IsChecked(); + UpdateUI(); + } + + void OnPassthroughScanButton(wxCommandEvent& event) + { + auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); + if (device != nullptr) + std::static_pointer_cast(device) + ->TriggerSyncButtonPressedEvent(); + event.Skip(); + } + + void OnPassthroughResetButton(wxCommandEvent& event) + { + auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); + if (device != nullptr) + std::static_pointer_cast(device) + ->TriggerSyncButtonHeldEvent(); + event.Skip(); + } + void OnEnableSpeaker(wxCommandEvent& event) { SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked(); event.Skip(); } + void UpdateUI() + { + const bool enable_bt_passthrough_mode = SConfig::GetInstance().m_bt_passthrough_enabled; + m_real_wiimotes_sizer->ShowItems(!enable_bt_passthrough_mode); + m_bt_passthrough_sizer->ShowItems(enable_bt_passthrough_mode); + m_unsupported_bt_text->Show(!enable_bt_passthrough_mode); + m_bt_passthrough_text->Show(enable_bt_passthrough_mode); + m_balance_board_group->ShowItems(!enable_bt_passthrough_mode); + m_enable_speaker_data->Enable(!enable_bt_passthrough_mode); + for (int i = 0; i < MAX_WIIMOTES; ++i) + { + m_wiimote_labels[i]->Enable(!enable_bt_passthrough_mode); + m_wiimote_sources[i]->Enable(!enable_bt_passthrough_mode); + m_wiimote_configure_button[i]->Enable(!enable_bt_passthrough_mode); + } + Layout(); + Fit(); + } + wxStaticBoxSizer* CreateGamecubeSizer(); wxStaticBoxSizer* CreateWiimoteConfigSizer(); wxStaticBoxSizer* CreateBalanceBoardSizer(); @@ -85,4 +134,14 @@ private: std::map m_wiimote_index_from_choice_id; std::map m_wiimote_index_from_config_id; std::array m_wiimote_configure_button; + + std::array m_wiimote_labels; + std::array m_wiimote_sources; + wxBoxSizer* m_real_wiimotes_sizer; + wxBoxSizer* m_bt_passthrough_sizer; + wxStaticText* m_unsupported_bt_text; + wxStaticText* m_bt_passthrough_text; + wxStaticBoxSizer* m_general_wm_settings; + wxStaticBoxSizer* m_balance_board_group; + wxCheckBox* m_enable_speaker_data; }; diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index 1cf24890aa..31dc2180be 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -270,4 +270,4 @@ - \ No newline at end of file + diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 18be3f9712..422867e904 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -43,6 +43,8 @@ #include "Core/HW/GCPad.h" #include "Core/HW/Wiimote.h" #include "Core/HotkeyManager.h" +#include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" #include "Core/Movie.h" #include "Core/State.h" @@ -1415,6 +1417,14 @@ void CFrame::ParseHotkeys() if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) AudioCommon::ToggleMuteVolume(); + if (SConfig::GetInstance().m_bt_passthrough_enabled) + { + auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); + if (device != nullptr) + std::static_pointer_cast(device) + ->UpdateSyncButtonState(IsHotkey(HK_TRIGGER_SYNC_BUTTON, true)); + } + // Wiimote connect and disconnect hotkeys int WiimoteId = -1; if (IsHotkey(HK_WIIMOTE1_CONNECT)) diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 2ab6b9b45c..29b8bca723 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -41,7 +41,7 @@ #include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/HotkeyManager.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/Movie.h" #include "Core/PowerPC/PPCSymbolDB.h" @@ -1565,7 +1565,8 @@ void CFrame::OnFifoPlayer(wxCommandEvent& WXUNUSED(event)) void CFrame::ConnectWiimote(int wm_idx, bool connect) { - if (Core::IsRunning() && SConfig::GetInstance().bWii) + if (Core::IsRunning() && SConfig::GetInstance().bWii && + !SConfig::GetInstance().m_bt_passthrough_enabled) { bool was_unpaused = Core::PauseAndLock(true); GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); @@ -1578,6 +1579,8 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect) void CFrame::OnConnectWiimote(wxCommandEvent& event) { + if (SConfig::GetInstance().m_bt_passthrough_enabled) + return; bool was_unpaused = Core::PauseAndLock(true); ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !GetUsbPointer() @@ -1721,7 +1724,6 @@ void CFrame::UpdateGUI() bool Running = Core::GetState() == Core::CORE_RUN; bool Paused = Core::GetState() == Core::CORE_PAUSE; bool Stopping = Core::GetState() == Core::CORE_STOPPING; - bool RunningWii = Initialized && SConfig::GetInstance().bWii; // Make sure that we have a toolbar if (m_ToolBar) @@ -1771,12 +1773,14 @@ void CFrame::UpdateGUI() // Tools GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Enable(RunningWii); - if (RunningWii) + bool ShouldEnableWiimotes = Initialized && SConfig::GetInstance().bWii && + !SConfig::GetInstance().m_bt_passthrough_enabled; + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(ShouldEnableWiimotes); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(ShouldEnableWiimotes); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(ShouldEnableWiimotes); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Enable(ShouldEnableWiimotes); + GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Enable(ShouldEnableWiimotes); + if (ShouldEnableWiimotes) { bool was_unpaused = Core::PauseAndLock(true); GetMenuBar() diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp index c954539e79..8e8512c07d 100644 --- a/Source/Core/DolphinWX/MainNoGUI.cpp +++ b/Source/Core/DolphinWX/MainNoGUI.cpp @@ -23,7 +23,7 @@ #include "Core/Core.h" #include "Core/HW/Wiimote.h" #include "Core/Host.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/State.h" @@ -139,7 +139,8 @@ bool Host_RendererIsFullscreen() void Host_ConnectWiimote(int wm_idx, bool connect) { - if (Core::IsRunning() && SConfig::GetInstance().bWii) + if (Core::IsRunning() && SConfig::GetInstance().bWii && + !SConfig::GetInstance().m_bt_passthrough_enabled) { Core::QueueHostJob([=] { bool was_unpaused = Core::PauseAndLock(true); From 419a9c55e47dab19cd22f2f74e1cade3e35c4492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 11 Sep 2016 12:34:14 +0200 Subject: [PATCH 3/8] WII_IPC_HLE/57e_305: Fake CommandReadBufferSize replies Apparently, Nintendo's Bluetooth stack expects the ACL packet buffer size to be limited to 10. Reporting anything higher than that could cause memory corruption, which can result in warning messages in the logs ("event mismatch"), and more annoyingly, random disconnects. Thanks to shuffle2 for the fix! --- .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h | 5 +++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp | 10 ++--- .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h | 5 +-- .../WII_IPC_HLE_Device_usb_bt_real.cpp | 37 +++++++++++++++++++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h | 4 ++ 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h index 2b7b230e1c..dee774905b 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h @@ -28,6 +28,11 @@ public: virtual void TriggerSyncButtonPressedEvent() {} virtual void TriggerSyncButtonHeldEvent() {} protected: + static constexpr int ACL_PKT_SIZE = 339; + static constexpr int ACL_PKT_NUM = 10; + static constexpr int SCO_PKT_SIZE = 64; + static constexpr int SCO_PKT_NUM = 0; + enum USBIOCtl { USBV0_IOCTL_CTRLMSG = 0, diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp index 46a3669f54..58772cde85 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp @@ -521,7 +521,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::ACLPool::Store(const u8* data, con return; } - _dbg_assert_msg_(WII_IPC_WIIMOTE, size < m_acl_pkt_size, "ACL packet too large for pool"); + _dbg_assert_msg_(WII_IPC_WIIMOTE, size < ACL_PKT_SIZE, "ACL packet too large for pool"); m_queue.push_back(Packet()); auto& packet = m_queue.back(); @@ -1824,13 +1824,13 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadBufferSize(const u8* in { hci_read_buffer_size_rp reply; reply.status = 0x00; - reply.max_acl_size = m_acl_pkt_size; + reply.max_acl_size = ACL_PKT_SIZE; // Due to how the widcomm stack which Nintendo uses is coded, we must never // let the stack think the controller is buffering more than 10 data packets // - it will cause a u8 underflow and royally screw things up. - reply.num_acl_pkts = m_acl_pkts_num; - reply.max_sco_size = 64; - reply.num_sco_pkts = 0; + reply.num_acl_pkts = ACL_PKT_NUM; + reply.max_sco_size = SCO_PKT_SIZE; + reply.num_sco_pkts = SCO_PKT_NUM; INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BUFFER_SIZE:"); DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h index bdf5404d74..48b56820c5 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h @@ -95,14 +95,11 @@ private: u32 m_ACLSetup; CtrlBuffer m_ACLEndpoint; - static const int m_acl_pkt_size = 339; - static const int m_acl_pkts_num = 10; - class ACLPool { struct Packet { - u8 data[m_acl_pkt_size]; + u8 data[ACL_PKT_SIZE]; u16 size; u16 conn_handle; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp index ff5dcf0af4..7f9a4c7542 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp @@ -140,6 +140,12 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad case USBV0_IOCTL_CTRLMSG: { auto cmd = std::make_unique(cmd_buffer); + const u16 opcode = *reinterpret_cast(Memory::GetPointer(cmd->payload_addr)); + if (opcode == HCI_CMD_READ_BUFFER_SIZE) + { + m_fake_read_buffer_size_reply.Set(); + return GetNoReply(); + } auto buffer = std::vector(cmd->length + LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(buffer.data(), cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); @@ -156,6 +162,11 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad case USBV0_IOCTL_INTRMSG: { auto buffer = std::make_unique(cmd_buffer, command_address); + if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && m_fake_read_buffer_size_reply.TestAndClear()) + { + FakeReadBufferSizeReply(*buffer); + return GetNoReply(); + } if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && m_sync_button_state == SyncButtonState::Pressed) { @@ -241,6 +252,32 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIResetCommand() INFO_LOG(WII_IPC_WIIMOTE, "Sent a reset command to adapter"); } +// Due to how the widcomm stack which Nintendo uses is coded, we must never +// let the stack think the controller is buffering more than 10 data packets +// - it will cause a u8 underflow and royally screw things up. +// Therefore, the reply to this command has to be faked to avoid random, weird issues +// (including Wiimote disconnects and "event mismatch" warning messages). +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeReadBufferSizeReply(const CtrlBuffer& ctrl) +{ + u8* packet = Memory::GetPointer(ctrl.m_payload_addr); + auto* hci_event = reinterpret_cast(packet); + hci_event->EventType = HCI_EVENT_COMMAND_COMPL; + hci_event->PayloadLength = sizeof(SHCIEventCommand) - 2 + sizeof(hci_read_buffer_size_rp); + hci_event->PacketIndicator = 0x01; + hci_event->Opcode = HCI_CMD_READ_BUFFER_SIZE; + + hci_read_buffer_size_rp reply; + reply.status = 0x00; + reply.max_acl_size = ACL_PKT_SIZE; + reply.num_acl_pkts = ACL_PKT_NUM; + reply.max_sco_size = SCO_PKT_SIZE; + reply.num_sco_pkts = SCO_PKT_NUM; + + memcpy(packet + sizeof(SHCIEventCommand), &reply, sizeof(hci_read_buffer_size_rp)); + ctrl.SetRetVal(sizeof(SHCIEventCommand) + sizeof(hci_read_buffer_size_rp)); + EnqueueReply(ctrl.m_cmd_address); +} + void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, const u8 size) { diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h index 87a005a2be..2981896a39 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h @@ -64,7 +64,11 @@ private: Common::Flag m_thread_running; std::thread m_thread; + // Set when we received a command to read the buffer size, and we need to fake a reply + Common::Flag m_fake_read_buffer_size_reply; + void SendHCIResetCommand(); + void FakeReadBufferSizeReply(const CtrlBuffer& ctrl); void FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, u8 size); void FakeSyncButtonPressedEvent(const CtrlBuffer& ctrl); void FakeSyncButtonHeldEvent(const CtrlBuffer& ctrl); From e63b07f73bbd9c48c0435f58af76c5593d539a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 12 Sep 2016 20:25:36 +0200 Subject: [PATCH 4/8] ControllerConfigDiag: Improve the UI The ControllerConfigDiag design was getting confusing, so more significant changes needed to be done. Firstly, the GC controller and the Wiimote section layouts have been aligned for consistency. The Balance Board source chooser is a checkbox. The "general settings" that affect the SYSCONF have been moved to the Wii pane in the Config dialog. It makes more sense because those affect the Wii's settings in the NAND, unlike the other options. Another reason for moving it is that the Controller Config Dialog was getting pretty crowded, and the whole section is disabled when emulation is running, which is wasted space. The Wiimotes section is now organised by two radio buttons. One is for the Passthrough Mode, with sync/reset buttons under it; the other is the emulated Bluetooth mode, which still has the regular Wiimote source choosers, the Continuous Scanning controls and the Enable Speaker Data option (which only applies to the emulated BT mode). Hopefully this should make things a bit clearer and look cleaner. (This is a monolithic commit because separating UI changes is hard) --- .../Core/DolphinWX/Config/WiiConfigPane.cpp | 81 ++++ Source/Core/DolphinWX/Config/WiiConfigPane.h | 12 + .../Core/DolphinWX/ControllerConfigDiag.cpp | 452 +++++++++--------- Source/Core/DolphinWX/ControllerConfigDiag.h | 138 ++---- 4 files changed, 359 insertions(+), 324 deletions(-) diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp index dfbd600470..559bee6051 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "Core/ConfigManager.h" @@ -38,6 +39,9 @@ void WiiConfigPane::InitializeGUI() m_system_language_strings.Add(_("Traditional Chinese")); m_system_language_strings.Add(_("Korean")); + m_bt_sensor_bar_pos_strings.Add(_("Bottom")); + m_bt_sensor_bar_pos_strings.Add(_("Top")); + m_screensaver_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Screen Saver")); m_pal60_mode_checkbox = new wxCheckBox(this, wxID_ANY, _("Use PAL60 Mode (EuRGB60)")); m_aspect_ratio_choice = @@ -46,6 +50,15 @@ void WiiConfigPane::InitializeGUI() new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_system_language_strings); m_sd_card_checkbox = new wxCheckBox(this, wxID_ANY, _("Insert SD Card")); m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard")); + m_bt_sensor_bar_pos = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_bt_sensor_bar_pos_strings); + m_bt_sensor_bar_sens = new wxSlider(this, wxID_ANY, 0, 0, 4); + m_bt_speaker_volume = new wxSlider(this, wxID_ANY, 0, 0, 127); + m_bt_wiimote_motor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor")); + + // With some GTK themes, no minimum size will be applied - so do this manually here + m_bt_sensor_bar_sens->SetMinSize(wxSize(100, -1)); + m_bt_speaker_volume->SetMinSize(wxSize(100, -1)); m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this); m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this); @@ -54,6 +67,10 @@ void WiiConfigPane::InitializeGUI() m_sd_card_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnSDCardCheckBoxChanged, this); m_connect_keyboard_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnConnectKeyboardCheckBoxChanged, this); + m_bt_sensor_bar_pos->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSensorBarPosChanged, this); + m_bt_sensor_bar_sens->Bind(wxEVT_SLIDER, &WiiConfigPane::OnSensorBarSensChanged, this); + m_bt_speaker_volume->Bind(wxEVT_SLIDER, &WiiConfigPane::OnSpeakerVolumeChanged, this); + m_bt_wiimote_motor->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnWiimoteMotorChanged, this); m_screensaver_checkbox->SetToolTip(_("Dims the screen after five minutes of inactivity.")); m_pal60_mode_checkbox->SetToolTip(_("Sets the Wii display mode to 60Hz (480i) instead of 50Hz " @@ -77,6 +94,35 @@ void WiiConfigPane::InitializeGUI() misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan, wxALL, 5); + auto* const bt_sensor_bar_pos_sizer = new wxBoxSizer(wxHORIZONTAL); + bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0, + wxALIGN_CENTER_VERTICAL); + bt_sensor_bar_pos_sizer->Add(m_bt_sensor_bar_sens); + bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0, + wxALIGN_CENTER_VERTICAL); + + auto* const bt_speaker_volume_sizer = new wxBoxSizer(wxHORIZONTAL); + bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0, + wxALIGN_CENTER_VERTICAL); + bt_speaker_volume_sizer->Add(m_bt_speaker_volume); + bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0, + wxALIGN_CENTER_VERTICAL); + + wxGridBagSizer* const bt_settings_grid_sizer = new wxGridBagSizer(); + bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")), + wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, + 5); + bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5); + bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")), + wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, + 5); + bt_settings_grid_sizer->Add(bt_sensor_bar_pos_sizer, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5); + bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speaker Volume:")), + wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, + 5); + bt_settings_grid_sizer->Add(bt_speaker_volume_sizer, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5); + bt_settings_grid_sizer->Add(m_bt_wiimote_motor, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5); + wxStaticBoxSizer* const misc_settings_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Misc Settings")); misc_settings_static_sizer->Add(misc_settings_grid_sizer); @@ -86,9 +132,14 @@ void WiiConfigPane::InitializeGUI() device_settings_sizer->Add(m_sd_card_checkbox, 0, wxALL, 5); device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxALL, 5); + auto* const bt_settings_static_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remote Settings")); + bt_settings_static_sizer->Add(bt_settings_grid_sizer); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxALL, 5); main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxALL, 5); + main_sizer->Add(bt_settings_static_sizer, 0, wxEXPAND | wxALL, 5); SetSizer(main_sizer); } @@ -102,6 +153,11 @@ void WiiConfigPane::LoadGUIValues() m_sd_card_checkbox->SetValue(SConfig::GetInstance().m_WiiSDCard); m_connect_keyboard_checkbox->SetValue(SConfig::GetInstance().m_WiiKeyboard); + + m_bt_sensor_bar_pos->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("BT.BAR")); + m_bt_sensor_bar_sens->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SENS")); + m_bt_speaker_volume->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SPKV")); + m_bt_wiimote_motor->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.MOT")); } void WiiConfigPane::RefreshGUI() @@ -112,6 +168,11 @@ void WiiConfigPane::RefreshGUI() m_pal60_mode_checkbox->Disable(); m_aspect_ratio_choice->Disable(); m_system_language_choice->Disable(); + + m_bt_sensor_bar_pos->Disable(); + m_bt_sensor_bar_sens->Disable(); + m_bt_speaker_volume->Disable(); + m_bt_wiimote_motor->Disable(); } } @@ -153,6 +214,26 @@ void WiiConfigPane::OnAspectRatioChoiceChanged(wxCommandEvent& event) SConfig::GetInstance().m_SYSCONF->SetData("IPL.AR", m_aspect_ratio_choice->GetSelection()); } +void WiiConfigPane::OnSensorBarPosChanged(wxCommandEvent& event) +{ + SConfig::GetInstance().m_SYSCONF->SetData("BT.BAR", event.GetInt()); +} + +void WiiConfigPane::OnSensorBarSensChanged(wxCommandEvent& event) +{ + SConfig::GetInstance().m_SYSCONF->SetData("BT.SENS", event.GetInt()); +} + +void WiiConfigPane::OnSpeakerVolumeChanged(wxCommandEvent& event) +{ + SConfig::GetInstance().m_SYSCONF->SetData("BT.SPKV", event.GetInt()); +} + +void WiiConfigPane::OnWiimoteMotorChanged(wxCommandEvent& event) +{ + SConfig::GetInstance().m_SYSCONF->SetData("BT.MOT", event.GetInt()); +} + // Change from IPL.LNG value to IPL.SADR country code. // http://wiibrew.org/wiki/Country_Codes u8 WiiConfigPane::GetSADRCountryCode(DiscIO::Language language) diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.h b/Source/Core/DolphinWX/Config/WiiConfigPane.h index 9d875aa0e4..ac482277fd 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.h +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.h @@ -15,6 +15,7 @@ enum class Language; class wxCheckBox; class wxChoice; +class wxSlider; class WiiConfigPane final : public wxPanel { @@ -33,10 +34,16 @@ private: void OnSystemLanguageChoiceChanged(wxCommandEvent&); void OnAspectRatioChoiceChanged(wxCommandEvent&); + void OnSensorBarPosChanged(wxCommandEvent&); + void OnSensorBarSensChanged(wxCommandEvent&); + void OnSpeakerVolumeChanged(wxCommandEvent&); + void OnWiimoteMotorChanged(wxCommandEvent&); + static u8 GetSADRCountryCode(DiscIO::Language language); wxArrayString m_system_language_strings; wxArrayString m_aspect_ratio_strings; + wxArrayString m_bt_sensor_bar_pos_strings; wxCheckBox* m_screensaver_checkbox; wxCheckBox* m_pal60_mode_checkbox; @@ -44,4 +51,9 @@ private: wxCheckBox* m_connect_keyboard_checkbox; wxChoice* m_system_language_choice; wxChoice* m_aspect_ratio_choice; + + wxChoice* m_bt_sensor_bar_pos; + wxSlider* m_bt_sensor_bar_sens; + wxSlider* m_bt_speaker_volume; + wxCheckBox* m_bt_wiimote_motor; }; diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index e05250f3d8..58ddcbaf8a 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -2,14 +2,16 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include -#include #include #include + #include #include #include #include +#include +#include +#include #include #include #include @@ -17,7 +19,6 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" -#include "Common/SysConf.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/GCKeyboard.h" @@ -26,6 +27,8 @@ #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/HotkeyManager.h" +#include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" #include "DolphinWX/Config/GCAdapterConfigDiag.h" @@ -57,10 +60,75 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent) Bind(wxEVT_CLOSE_WINDOW, &ControllerConfigDiag::OnClose, this); Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnCloseButton, this, wxID_CLOSE); + UpdateUI(); + SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); + SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER); SetSizerAndFit(main_sizer); Center(); - UpdateUI(); +} + +void ControllerConfigDiag::UpdateUI() +{ + const bool enable_bt_passthrough_mode = SConfig::GetInstance().m_bt_passthrough_enabled; + + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + { + m_wiimote_labels[i]->Enable(!enable_bt_passthrough_mode); + m_wiimote_sources[i]->Enable(!enable_bt_passthrough_mode); + m_wiimote_configure_button[i]->Enable(!enable_bt_passthrough_mode); + + m_wiimote_sources[i]->Select(g_wiimote_sources[i]); + + const bool wii_game_started = + SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED; + if (Core::g_want_determinism || !wii_game_started) + m_wiimote_sources[i]->Disable(); + if (!wii_game_started || + (g_wiimote_sources[i] != WIIMOTE_SRC_EMU && g_wiimote_sources[i] != WIIMOTE_SRC_HYBRID)) + m_wiimote_configure_button[i]->Disable(); + } + + m_passthrough_sync_text->Enable(enable_bt_passthrough_mode); + m_passthrough_sync_btn->Enable(enable_bt_passthrough_mode); + m_passthrough_reset_text->Enable(enable_bt_passthrough_mode); + m_passthrough_reset_btn->Enable(enable_bt_passthrough_mode); + + m_balance_board_checkbox->Enable(!enable_bt_passthrough_mode); + m_enable_continuous_scanning->Enable(!enable_bt_passthrough_mode); + m_refresh_wm_button->Enable(!enable_bt_passthrough_mode); + m_unsupported_bt_text->Enable(!enable_bt_passthrough_mode); + m_enable_speaker_data->Enable(!enable_bt_passthrough_mode); + + // Disable some controls when emulation is running + if (Core::IsRunning()) + { + if (!SConfig::GetInstance().bWii || NetPlay::IsNetPlayRunning()) + { + m_passthrough_sync_text->Disable(); + m_passthrough_sync_btn->Disable(); + m_passthrough_reset_text->Disable(); + m_passthrough_reset_btn->Disable(); + + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + { + m_wiimote_labels[i]->Disable(); + m_wiimote_sources[i]->Disable(); + } + m_balance_board_checkbox->Disable(); + } + + m_passthrough_bt_radio->Disable(); + m_emulated_bt_radio->Disable(); + + if (!SConfig::GetInstance().bWii) + { + m_enable_continuous_scanning->Disable(); + m_refresh_wm_button->Disable(); + m_unsupported_bt_text->Disable(); + m_enable_speaker_data->Disable(); + } + } } wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() @@ -68,6 +136,7 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() wxStaticBoxSizer* const gamecube_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers")); wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5); + gamecube_flex_sizer->AddGrowableCol(1); wxStaticText* pad_labels[4]; wxChoice* pad_type_choices[4]; @@ -80,7 +149,7 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() const wxWindowID button_id = wxWindow::NewControlId(); m_gc_port_from_config_id.emplace(button_id, i); m_gc_port_configure_button[i] = - new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25)); + new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, -1)); m_gc_port_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, this); @@ -130,11 +199,11 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() // Add to the sizer gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL); - gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL); + gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND); gamecube_flex_sizer->Add(m_gc_port_configure_button[i], 1, wxEXPAND); } - gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5); + gamecube_static_sizer->Add(gamecube_flex_sizer, 0, wxEXPAND | wxALL, 5); gamecube_static_sizer->AddSpacer(5); return gamecube_static_sizer; @@ -142,13 +211,76 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() { + auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Wiimotes")); + + m_passthrough_bt_radio = new wxRadioButton(this, wxID_ANY, _("Passthrough a Bluetooth adapter"), + wxDefaultPosition, wxDefaultSize, wxRB_GROUP); + m_passthrough_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged, + this); + box->Add(m_passthrough_bt_radio, 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5); + box->Add(CreatePassthroughBTConfigSizer(), 0, wxALL | wxEXPAND, 5); + + box->AddSpacer(10); + + m_emulated_bt_radio = new wxRadioButton(this, wxID_ANY, _("Emulate the Wii's Bluetooth adapter")); + m_emulated_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged, this); + + box->Add(m_emulated_bt_radio, 0, wxALL | wxEXPAND, 5); + box->Add(CreateEmulatedBTConfigSizer(), 0, wxALL | wxEXPAND, 5); + box->AddSpacer(5); + + if (SConfig::GetInstance().m_bt_passthrough_enabled) + m_passthrough_bt_radio->SetValue(true); + else + m_emulated_bt_radio->SetValue(true); + + return box; +} + +wxBoxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer() +{ + auto* const sizer = new wxBoxSizer(wxVERTICAL); + + m_passthrough_sync_text = new wxStaticText(this, wxID_ANY, _("Sync real Wiimotes and pair them")); + m_passthrough_sync_btn = + new wxButton(this, wxID_ANY, _("Sync"), wxDefaultPosition, wxSize(100, -1)); + m_passthrough_sync_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughScanButton, this); + + m_passthrough_reset_text = + new wxStaticText(this, wxID_ANY, _("Reset all saved Wiimote pairings")); + m_passthrough_reset_btn = + new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxSize(100, -1)); + m_passthrough_reset_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton, + this); + + auto* const sync_sizer = new wxBoxSizer(wxHORIZONTAL); + sync_sizer->Add(m_passthrough_sync_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + sync_sizer->AddStretchSpacer(); + sync_sizer->Add(m_passthrough_sync_btn, 0, wxEXPAND); + auto* const reset_sizer = new wxBoxSizer(wxHORIZONTAL); + reset_sizer->Add(m_passthrough_reset_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + reset_sizer->AddStretchSpacer(); + reset_sizer->Add(m_passthrough_reset_btn, 0, wxEXPAND); + + sizer->Add(sync_sizer, 0, wxEXPAND); + sizer->AddSpacer(5); + sizer->Add(reset_sizer, 0, wxEXPAND); + return sizer; +} + +wxBoxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer() +{ + static const std::array src_choices = { + {_("None"), _("Emulated Wiimote"), _("Real Wiimote"), _("Hybrid Wiimote")}}; + + auto* const sizer = new wxBoxSizer(wxVERTICAL); + + // Source selector grid + auto* const grid = new wxFlexGridSizer(3, 5, 5); + grid->AddGrowableCol(1); + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) { - wxString wiimote_str = wxString::Format(_("Wiimote %i"), i + 1); - - static const std::array src_choices = { - {_("None"), _("Emulated Wiimote"), _("Real Wiimote"), _("Hybrid Wiimote")}}; - // reserve four ids, so that we can calculate the index from the ids later on // Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more // complicated.. @@ -158,234 +290,61 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() int config_bt_id = wxWindow::NewControlId(); m_wiimote_index_from_config_id.emplace(config_bt_id, i); - m_wiimote_labels[i] = new wxStaticText(this, wxID_ANY, wiimote_str); + m_wiimote_labels[i] = + new wxStaticText(this, wxID_ANY, wxString::Format(_("Wiimote %i"), i + 1)); m_wiimote_sources[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, src_choices.size(), src_choices.data()); m_wiimote_sources[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this); + m_wiimote_configure_button[i] = - new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(80, 25)); + new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(100, -1)); m_wiimote_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteConfigButton, this); - // Disable controller type selection for certain circumstances. - bool wii_game_started = - SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED; - if (Core::g_want_determinism || !wii_game_started) - m_wiimote_sources[i]->Disable(); - - m_wiimote_sources[i]->Select(g_wiimote_sources[i]); - if (!wii_game_started || - (g_wiimote_sources[i] != WIIMOTE_SRC_EMU && g_wiimote_sources[i] != WIIMOTE_SRC_HYBRID)) - m_wiimote_configure_button[i]->Disable(); + grid->Add(m_wiimote_labels[i], 0, wxALIGN_CENTER_VERTICAL); + grid->Add(m_wiimote_sources[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND); + grid->Add(m_wiimote_configure_button[i], 1, wxEXPAND); } - // "Wiimotes" layout - wxStaticBoxSizer* const wiimote_group = new wxStaticBoxSizer(wxVERTICAL, this, _("Wiimotes")); - wxBoxSizer* const wiimote_control_section = new wxBoxSizer(wxHORIZONTAL); - wxFlexGridSizer* const wiimote_sizer = new wxFlexGridSizer(3, 5, 5); - for (unsigned int i = 0; i < 4; ++i) - { - wiimote_sizer->Add(m_wiimote_labels[i], 0, wxALIGN_CENTER_VERTICAL); - wiimote_sizer->Add(m_wiimote_sources[i], 0, wxALIGN_CENTER_VERTICAL); - wiimote_sizer->Add(m_wiimote_configure_button[i]); - } - wiimote_control_section->Add(wiimote_sizer, 1, wxEXPAND, 5); + sizer->Add(grid, 0, wxEXPAND); + sizer->AddSpacer(5); - // Disable some controls when emulation is running - if (Core::GetState() != Core::CORE_UNINITIALIZED && NetPlay::IsNetPlayRunning()) - { - for (int i = 0; i < 4; ++i) - { - m_wiimote_labels[i]->Disable(); - m_wiimote_sources[i]->Disable(); - } - } - - wiimote_group->Add(wiimote_control_section, 0, wxEXPAND); - wiimote_group->AddSpacer(5); - wiimote_group->Add(CreateBalanceBoardSizer(), 0, wxEXPAND); - wiimote_group->AddSpacer(5); - wiimote_group->Add(CreateRealWiimoteSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); - wiimote_group->AddSpacer(5); - m_general_wm_settings = CreateGeneralWiimoteSettingsSizer(); - wiimote_group->Add(m_general_wm_settings, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); - - return wiimote_group; -} - -wxStaticBoxSizer* ControllerConfigDiag::CreateBalanceBoardSizer() -{ - m_balance_board_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Balance Board")); - wxFlexGridSizer* const bb_sizer = new wxFlexGridSizer(1, 5, 5); - int source_ctrl_id = wxWindow::NewControlId(); - - m_wiimote_index_from_choice_id.emplace(source_ctrl_id, WIIMOTE_BALANCE_BOARD); - - static const std::array src_choices = {{_("None"), _("Real Balance Board")}}; - - wxChoice* const bb_source = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, - src_choices.size(), src_choices.data()); - bb_source->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this); - - bb_source->Select(g_wiimote_sources[WIIMOTE_BALANCE_BOARD] ? 1 : 0); - - bb_sizer->Add(bb_source, 0, wxALIGN_CENTER_VERTICAL); - - m_balance_board_group->Add(bb_sizer, 1, wxEXPAND, 5); - - // Disable when emulation is running. - if (Core::GetState() != Core::CORE_UNINITIALIZED) - bb_source->Disable(); - - return m_balance_board_group; -} - -wxStaticBoxSizer* ControllerConfigDiag::CreateRealWiimoteSizer() -{ - auto* const real_wiimotes_group = new wxStaticBoxSizer(wxVERTICAL, this, _("Real Wiimotes")); + // Scanning controls + m_enable_continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning")); + m_enable_continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning, + this); + m_enable_continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning); + m_refresh_wm_button = + new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxSize(100, -1)); + m_refresh_wm_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this); m_unsupported_bt_text = - new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found.\n" - "You must manually connect your Wiimotes.")); - real_wiimotes_group->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxALL, 5); + new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found,\n" + "so you must connect Wiimotes manually.")); m_unsupported_bt_text->Show(!WiimoteReal::g_wiimote_scanner.IsReady()); + sizer->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxALL, 5); - // Bluetooth adapter passthrough - m_bt_passthrough_text = new wxStaticText( - this, wxID_ANY, _("A Bluetooth adapter will be passed through to the game.\n" - "Only real Wiimotes will be usable.\n" - "Wiimotes can be synced to Dolphin with the sync hotkey.")); - real_wiimotes_group->Add(m_bt_passthrough_text, 0, wxALIGN_CENTER | wxALL, 5); + auto* const scanning_sizer = new wxBoxSizer(wxHORIZONTAL); + scanning_sizer->Add(m_enable_continuous_scanning, 0, wxALIGN_CENTER_VERTICAL); + scanning_sizer->AddStretchSpacer(); + scanning_sizer->Add(m_refresh_wm_button, 0, wxALL | wxEXPAND); + sizer->Add(scanning_sizer, 0, wxEXPAND); - auto* const enable_passthrough = - new wxCheckBox(this, wxID_ANY, _("Enable Bluetooth Adapter Passthrough")); - enable_passthrough->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnPassthroughMode, this); - enable_passthrough->SetValue(SConfig::GetInstance().m_bt_passthrough_enabled); - - auto* const wm_bt_sync_button = new wxButton(this, wxID_ANY, _("Sync Wiimotes")); - wm_bt_sync_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughScanButton, this); - auto* const wm_bt_reset_button = new wxButton(this, wxID_ANY, _("Reset pairings")); - wm_bt_reset_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton, this); - - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - enable_passthrough->Disable(); - if (!SConfig::GetInstance().bWii) - m_bt_passthrough_text->Disable(); - } - - if (!SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED) - { - wm_bt_sync_button->Disable(); - wm_bt_reset_button->Disable(); - } - - m_bt_passthrough_sizer = new wxBoxSizer(wxHORIZONTAL); - m_bt_passthrough_sizer->Add(wm_bt_sync_button, 0, wxALIGN_CENTER_VERTICAL); - m_bt_passthrough_sizer->Add(wm_bt_reset_button, 0, wxALL | wxALIGN_CENTER, 5); - - // Regular real Wiimotes controls - auto* const continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning")); - continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning, this); - continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning); - auto* const wm_refresh_button = new wxButton(this, wxID_ANY, _("Refresh")); - wm_refresh_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this); - - m_real_wiimotes_sizer = new wxBoxSizer(wxHORIZONTAL); - m_real_wiimotes_sizer->Add(continuous_scanning, 0, wxALIGN_CENTER_VERTICAL); - m_real_wiimotes_sizer->AddStretchSpacer(); - m_real_wiimotes_sizer->Add(wm_refresh_button, 0, wxALL | wxALIGN_CENTER, 5); - - real_wiimotes_group->Add(enable_passthrough, 0); - real_wiimotes_group->Add(m_bt_passthrough_sizer, 0, wxEXPAND); - real_wiimotes_group->Add(m_real_wiimotes_sizer, 0, wxEXPAND); - - return real_wiimotes_group; -} - -wxStaticBoxSizer* ControllerConfigDiag::CreateGeneralWiimoteSettingsSizer() -{ - const wxString str[] = {_("Bottom"), _("Top")}; - wxChoice* const WiiSensBarPos = - new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 2, str); - wxSlider* const WiiSensBarSens = new wxSlider(this, wxID_ANY, 0, 0, 4); - wxSlider* const WiimoteSpkVolume = new wxSlider(this, wxID_ANY, 0, 0, 127); - wxCheckBox* const WiimoteMotor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor")); + // Balance Board + m_balance_board_checkbox = new wxCheckBox(this, wxID_ANY, _("Real Balance Board")); + m_balance_board_checkbox->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnBalanceBoardChanged, + this); + m_balance_board_checkbox->SetValue(g_wiimote_sources[WIIMOTE_BALANCE_BOARD] == WIIMOTE_SRC_REAL); + sizer->Add(m_balance_board_checkbox); + sizer->AddSpacer(5); + // Speaker data m_enable_speaker_data = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data")); m_enable_speaker_data->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this); m_enable_speaker_data->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker); + sizer->Add(m_enable_speaker_data); - wxStaticText* const WiiSensBarPosText = - new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")); - wxStaticText* const WiiSensBarSensText = new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")); - wxStaticText* const WiiSensBarSensMinText = new wxStaticText(this, wxID_ANY, _("Min")); - wxStaticText* const WiiSensBarSensMaxText = new wxStaticText(this, wxID_ANY, _("Max")); - wxStaticText* const WiimoteSpkVolumeText = new wxStaticText(this, wxID_ANY, _("Speaker Volume:")); - wxStaticText* const WiimoteSpkVolumeMinText = new wxStaticText(this, wxID_ANY, _("Min")); - wxStaticText* const WiimoteSpkVolumeMaxText = new wxStaticText(this, wxID_ANY, _("Max")); - - // With some GTK themes, no minimum size will be applied - so do this manually here - WiiSensBarSens->SetMinSize(wxSize(100, -1)); - WiimoteSpkVolume->SetMinSize(wxSize(100, -1)); - - // Disable some controls when emulation is running - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - WiiSensBarPos->Disable(); - WiiSensBarSens->Disable(); - WiimoteSpkVolume->Disable(); - WiimoteMotor->Disable(); - WiiSensBarPosText->Disable(); - WiiSensBarSensText->Disable(); - WiiSensBarSensMinText->Disable(); - WiiSensBarSensMaxText->Disable(); - WiimoteSpkVolumeText->Disable(); - WiimoteSpkVolumeMinText->Disable(); - WiimoteSpkVolumeMaxText->Disable(); - } - - // "General Settings" initialization - WiiSensBarPos->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("BT.BAR")); - WiiSensBarSens->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SENS")); - WiimoteSpkVolume->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SPKV")); - WiimoteMotor->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.MOT")); - - WiiSensBarPos->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnSensorBarPos, this); - WiiSensBarSens->Bind(wxEVT_SLIDER, &ControllerConfigDiag::OnSensorBarSensitivity, this); - WiimoteSpkVolume->Bind(wxEVT_SLIDER, &ControllerConfigDiag::OnSpeakerVolume, this); - WiimoteMotor->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnMotor, this); - - // "General Settings" layout - wxStaticBoxSizer* const general_sizer = - new wxStaticBoxSizer(wxVERTICAL, this, _("General Settings")); - wxFlexGridSizer* const choice_sizer = new wxFlexGridSizer(2, 5, 5); - - wxBoxSizer* const sensbarsens_sizer = new wxBoxSizer(wxHORIZONTAL); - sensbarsens_sizer->Add(WiiSensBarSensMinText, 0, wxALIGN_CENTER_VERTICAL); - sensbarsens_sizer->Add(WiiSensBarSens); - sensbarsens_sizer->Add(WiiSensBarSensMaxText, 0, wxALIGN_CENTER_VERTICAL); - - wxBoxSizer* const spkvol_sizer = new wxBoxSizer(wxHORIZONTAL); - spkvol_sizer->Add(WiimoteSpkVolumeMinText, 0, wxALIGN_CENTER_VERTICAL); - spkvol_sizer->Add(WiimoteSpkVolume); - spkvol_sizer->Add(WiimoteSpkVolumeMaxText, 0, wxALIGN_CENTER_VERTICAL); - - choice_sizer->Add(WiiSensBarPosText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(WiiSensBarPos); - choice_sizer->Add(WiiSensBarSensText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(sensbarsens_sizer); - choice_sizer->Add(WiimoteSpkVolumeText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(spkvol_sizer); - - wxGridSizer* const general_wiimote_sizer = new wxGridSizer(1, 5, 5); - general_wiimote_sizer->Add(WiimoteMotor); - general_wiimote_sizer->Add(m_enable_speaker_data); - - general_sizer->Add(choice_sizer); - general_sizer->Add(general_wiimote_sizer); - - return general_sizer; + return sizer; } void ControllerConfigDiag::OnClose(wxCloseEvent& event) @@ -393,7 +352,6 @@ void ControllerConfigDiag::OnClose(wxCloseEvent& event) // Save all settings SConfig::GetInstance().SaveSettings(); SaveWiimoteSource(); - EndModal(wxID_OK); } @@ -525,11 +483,63 @@ void ControllerConfigDiag::OnWiimoteConfigButton(wxCommandEvent& ev) HotkeyManagerEmu::Enable(true); } +void ControllerConfigDiag::OnBluetoothModeChanged(wxCommandEvent& event) +{ + SConfig::GetInstance().m_bt_passthrough_enabled = m_passthrough_bt_radio->GetValue(); + WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); + UpdateUI(); +} + +void ControllerConfigDiag::OnPassthroughScanButton(wxCommandEvent& event) +{ + if (!Core::IsRunning()) + { + wxMessageBox(_("A sync can only be triggered when a Wii game is running."), _("Sync Wiimotes"), + wxICON_WARNING); + return; + } + auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); + if (device != nullptr) + std::static_pointer_cast(device) + ->TriggerSyncButtonPressedEvent(); +} + +void ControllerConfigDiag::OnPassthroughResetButton(wxCommandEvent& event) +{ + if (!Core::IsRunning()) + { + wxMessageBox(_("Saved Wiimote pairings can only be reset when a Wii game is running."), + _("Reset Wiimote pairings"), wxICON_WARNING); + return; + } + auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); + if (device != nullptr) + std::static_pointer_cast(device) + ->TriggerSyncButtonHeldEvent(); +} + +void ControllerConfigDiag::OnBalanceBoardChanged(wxCommandEvent& event) +{ + WiimoteReal::ChangeWiimoteSource(WIIMOTE_BALANCE_BOARD, + event.IsChecked() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE); +} + +void ControllerConfigDiag::OnContinuousScanning(wxCommandEvent& event) +{ + SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked(); + WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); +} + void ControllerConfigDiag::OnWiimoteRefreshButton(wxCommandEvent&) { WiimoteReal::Refresh(); } +void ControllerConfigDiag::OnEnableSpeaker(wxCommandEvent& event) +{ + SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked(); +} + void ControllerConfigDiag::SaveWiimoteSource() { std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini"; diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index f8b4ef3a2c..48a8e4b9fe 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -6,142 +6,74 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include "Common/SysConf.h" +#include + #include "Core/ConfigManager.h" #include "Core/HW/Wiimote.h" -#include "Core/IPC_HLE/WII_IPC_HLE.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h" #include "InputCommon/GCAdapter.h" class InputConfig; +class wxCheckBox; +class wxChoice; +class wxRadioButton; +class wxStaticBoxSizer; +class wxStaticText; -class ControllerConfigDiag : public wxDialog +class ControllerConfigDiag final : public wxDialog { public: ControllerConfigDiag(wxWindow* const parent); private: - void OnSensorBarPos(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.BAR", event.GetInt()); - event.Skip(); - } - - void OnSensorBarSensitivity(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.SENS", event.GetInt()); - event.Skip(); - } - - void OnSpeakerVolume(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.SPKV", event.GetInt()); - event.Skip(); - } - - void OnMotor(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.MOT", event.GetInt()); - event.Skip(); - } - - void OnContinuousScanning(wxCommandEvent& event) - { - SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked(); - WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); - event.Skip(); - } - - void OnPassthroughMode(wxCommandEvent& event) - { - SConfig::GetInstance().m_bt_passthrough_enabled = event.IsChecked(); - UpdateUI(); - } - - void OnPassthroughScanButton(wxCommandEvent& event) - { - auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); - if (device != nullptr) - std::static_pointer_cast(device) - ->TriggerSyncButtonPressedEvent(); - event.Skip(); - } - - void OnPassthroughResetButton(wxCommandEvent& event) - { - auto device = WII_IPC_HLE_Interface::GetDeviceByName("/dev/usb/oh1/57e/305"); - if (device != nullptr) - std::static_pointer_cast(device) - ->TriggerSyncButtonHeldEvent(); - event.Skip(); - } - - void OnEnableSpeaker(wxCommandEvent& event) - { - SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked(); - event.Skip(); - } - - void UpdateUI() - { - const bool enable_bt_passthrough_mode = SConfig::GetInstance().m_bt_passthrough_enabled; - m_real_wiimotes_sizer->ShowItems(!enable_bt_passthrough_mode); - m_bt_passthrough_sizer->ShowItems(enable_bt_passthrough_mode); - m_unsupported_bt_text->Show(!enable_bt_passthrough_mode); - m_bt_passthrough_text->Show(enable_bt_passthrough_mode); - m_balance_board_group->ShowItems(!enable_bt_passthrough_mode); - m_enable_speaker_data->Enable(!enable_bt_passthrough_mode); - for (int i = 0; i < MAX_WIIMOTES; ++i) - { - m_wiimote_labels[i]->Enable(!enable_bt_passthrough_mode); - m_wiimote_sources[i]->Enable(!enable_bt_passthrough_mode); - m_wiimote_configure_button[i]->Enable(!enable_bt_passthrough_mode); - } - Layout(); - Fit(); - } + void UpdateUI(); wxStaticBoxSizer* CreateGamecubeSizer(); wxStaticBoxSizer* CreateWiimoteConfigSizer(); - wxStaticBoxSizer* CreateBalanceBoardSizer(); - wxStaticBoxSizer* CreateRealWiimoteSizer(); - wxStaticBoxSizer* CreateGeneralWiimoteSettingsSizer(); + wxBoxSizer* CreatePassthroughBTConfigSizer(); + wxBoxSizer* CreateEmulatedBTConfigSizer(); void OnClose(wxCloseEvent& event); void OnCloseButton(wxCommandEvent& event); - void OnGameCubePortChanged(wxCommandEvent& event); - void OnGameCubeConfigButton(wxCommandEvent& event); - void OnWiimoteSourceChanged(wxCommandEvent& event); void OnWiimoteConfigButton(wxCommandEvent& event); void OnWiimoteRefreshButton(wxCommandEvent& event); void SaveWiimoteSource(); + void OnGameCubePortChanged(wxCommandEvent& event); + void OnGameCubeConfigButton(wxCommandEvent& event); + + void OnBluetoothModeChanged(wxCommandEvent& event); + + void OnPassthroughScanButton(wxCommandEvent& event); + void OnPassthroughResetButton(wxCommandEvent& event); + void OnBalanceBoardChanged(wxCommandEvent& event); + void OnContinuousScanning(wxCommandEvent& event); + void OnEnableSpeaker(wxCommandEvent& event); + std::map m_gc_port_from_choice_id; std::map m_gc_port_from_config_id; std::array m_gc_port_configure_button; std::array m_gc_pad_type_strs; + wxRadioButton* m_passthrough_bt_radio; + wxRadioButton* m_emulated_bt_radio; + + wxStaticText* m_passthrough_sync_text; + wxButton* m_passthrough_sync_btn; + wxStaticText* m_passthrough_reset_text; + wxButton* m_passthrough_reset_btn; + std::map m_wiimote_index_from_choice_id; std::map m_wiimote_index_from_config_id; std::array m_wiimote_configure_button; + std::array m_wiimote_labels; + std::array m_wiimote_sources; + wxCheckBox* m_balance_board_checkbox; - std::array m_wiimote_labels; - std::array m_wiimote_sources; - wxBoxSizer* m_real_wiimotes_sizer; - wxBoxSizer* m_bt_passthrough_sizer; + wxCheckBox* m_enable_continuous_scanning; + wxButton* m_refresh_wm_button; wxStaticText* m_unsupported_bt_text; - wxStaticText* m_bt_passthrough_text; - wxStaticBoxSizer* m_general_wm_settings; - wxStaticBoxSizer* m_balance_board_group; wxCheckBox* m_enable_speaker_data; }; From 5b50b1e1aa3923fa46c3407885d44a7cbc570d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Fri, 16 Sep 2016 23:25:57 +0200 Subject: [PATCH 5/8] WII_IPC_HLE/57e_305: Store link keys This stores the address of paired devices and associated link keys. It is needed because some adapters forget all stored link keys when they are reset, which breaks pairings because the Wii relies on the Bluetooth module to remember them. It doesn't fix adapters that can't remember any link key at all and always return 0 for the number of stored/written link keys. For those adapters, there is no fix. This also improves the usability of passthrough mode for adapters that already work, since pairings will now keep working even if the link keys get cleared by something else (for example by the host Bluetooth stack). --- Source/Core/Core/ConfigManager.cpp | 3 + Source/Core/Core/ConfigManager.h | 1 + .../WII_IPC_HLE_Device_usb_bt_real.cpp | 188 ++++++++++++++++++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h | 12 ++ 4 files changed, 204 insertions(+) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 6e896658ef..b6b74e5160 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -55,6 +55,7 @@ void SConfig::SaveSettings() NOTICE_LOG(BOOT, "Saving settings to %s", File::GetUserPath(F_DOLPHINCONFIG_IDX).c_str()); IniFile ini; ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); // load first to not kill unknown stuff + m_SYSCONF->Reload(); SaveGeneralSettings(ini); SaveInterfaceSettings(ini); @@ -330,6 +331,7 @@ void SConfig::SaveBluetoothPassthroughSettings(IniFile& ini) section->Set("Enabled", m_bt_passthrough_enabled); section->Set("VID", m_bt_passthrough_vid); section->Set("PID", m_bt_passthrough_pid); + section->Set("LinkKeys", m_bt_passthrough_link_keys); } void SConfig::LoadSettings() @@ -622,6 +624,7 @@ void SConfig::LoadBluetoothPassthroughSettings(IniFile& ini) section->Get("Enabled", &m_bt_passthrough_enabled, false); section->Get("VID", &m_bt_passthrough_vid, -1); section->Get("PID", &m_bt_passthrough_pid, -1); + section->Get("LinkKeys", &m_bt_passthrough_link_keys, ""); } void SConfig::LoadDefaults() diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 2bb649fcbc..f2275bb4c4 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -147,6 +147,7 @@ struct SConfig : NonCopyable bool m_bt_passthrough_enabled = false; int m_bt_passthrough_pid = -1; int m_bt_passthrough_vid = -1; + std::string m_bt_passthrough_link_keys; // Fifo Player related settings bool bLoopFifoReplay = true; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp index 7f9a4c7542..b6a5b5b8db 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include +#include #include #include @@ -15,6 +18,12 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h" #include "Core/IPC_HLE/hci.h" +// This stores the address of paired devices and associated link keys. +// It is needed because some adapters forget all stored link keys when they are reset, +// which breaks pairings because the Wii relies on the Bluetooth module to remember them. +static std::map s_link_keys; +static Common::Flag s_need_reset_keys; + // This flag is set when a libusb transfer failed (for reasons other than timing out) // and we showed an OSD message about it. static Common::Flag s_showed_failed_transfer; @@ -41,6 +50,8 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305_real::CWII_IPC_HLE_Device_usb_oh1_57e_305_re { const int ret = libusb_init(&m_libusb_context); _assert_msg_(WII_IPC_WIIMOTE, ret == 0, "Failed to init libusb."); + + LoadLinkKeys(); } CWII_IPC_HLE_Device_usb_oh1_57e_305_real::~CWII_IPC_HLE_Device_usb_oh1_57e_305_real() @@ -48,6 +59,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305_real::~CWII_IPC_HLE_Device_usb_oh1_57e_305_r if (m_handle != nullptr) { SendHCIResetCommand(); + WaitForHCICommandComplete(HCI_CMD_RESET); libusb_release_interface(m_handle, 0); // libusb_handle_events() may block the libusb thread indefinitely, so we need to // call libusb_close() first then immediately stop the thread in StopTransferThread. @@ -56,6 +68,8 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305_real::~CWII_IPC_HLE_Device_usb_oh1_57e_305_r } libusb_exit(m_libusb_context); + + SaveLinkKeys(); } IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::Open(u32 command_address, u32 mode) @@ -94,6 +108,8 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::Open(u32 command_addr NOTICE_LOG(WII_IPC_WIIMOTE, "Using device %04x:%04x (rev %x) for Bluetooth: %s %s %s", device_descriptor.idVendor, device_descriptor.idProduct, device_descriptor.bcdDevice, manufacturer, product, serial_number); + m_is_wii_bt_module = + device_descriptor.idVendor == 0x57e && device_descriptor.idProduct == 0x305; libusb_free_config_descriptor(config_descriptor); break; } @@ -133,6 +149,15 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::Close(u32 command_add IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_address) { + if (!m_is_wii_bt_module && s_need_reset_keys.TestAndClear()) + { + // Do this now before transferring any more data, so that this is fully transparent to games + SendHCIDeleteLinkKeyCommand(); + WaitForHCICommandComplete(HCI_CMD_DELETE_STORED_LINK_KEY); + if (SendHCIStoreLinkKeyCommand()) + WaitForHCICommandComplete(HCI_CMD_WRITE_STORED_LINK_KEY); + } + const SIOCtlVBuffer cmd_buffer(command_address); switch (cmd_buffer.Parameter) { @@ -146,6 +171,22 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad m_fake_read_buffer_size_reply.Set(); return GetNoReply(); } + if (opcode == HCI_CMD_DELETE_STORED_LINK_KEY) + { + // Delete link key(s) from our own link key storage when the game tells the adapter to + const auto* delete_cmd = + reinterpret_cast(Memory::GetPointer(cmd->payload_addr)); + if (delete_cmd->delete_all) + { + s_link_keys.clear(); + } + else + { + btaddr_t addr; + std::copy(std::begin(delete_cmd->bdaddr.b), std::end(delete_cmd->bdaddr.b), addr.begin()); + s_link_keys.erase(addr); + } + } auto buffer = std::vector(cmd->length + LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(buffer.data(), cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); @@ -242,6 +283,21 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TriggerSyncButtonHeldEvent() m_sync_button_state = SyncButtonState::LongPressed; } +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::WaitForHCICommandComplete(const u16 opcode) +{ + int actual_length; + std::vector buffer(1024); + // Only try 100 transfers at most, to avoid being stuck in an infinite loop + for (int tries = 0; tries < 100; ++tries) + { + if (libusb_interrupt_transfer(m_handle, HCI_EVENT, buffer.data(), + static_cast(buffer.size()), &actual_length, 20) == 0 && + reinterpret_cast(buffer.data())->event == HCI_EVENT_COMMAND_COMPL && + reinterpret_cast(buffer.data())->Opcode == opcode) + break; + } +} + void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIResetCommand() { const u8 type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE; @@ -252,6 +308,62 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIResetCommand() INFO_LOG(WII_IPC_WIIMOTE, "Sent a reset command to adapter"); } +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIDeleteLinkKeyCommand() +{ + const u8 type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE; + std::vector packet(sizeof(hci_cmd_hdr_t) + sizeof(hci_delete_stored_link_key_cp)); + + auto* header = reinterpret_cast(packet.data()); + header->opcode = HCI_CMD_DELETE_STORED_LINK_KEY; + header->length = sizeof(hci_delete_stored_link_key_cp); + auto* cmd = + reinterpret_cast(packet.data() + sizeof(hci_cmd_hdr_t)); + cmd->bdaddr = {}; + cmd->delete_all = true; + + libusb_control_transfer(m_handle, type, 0, 0, 0, packet.data(), static_cast(packet.size()), + TIMEOUT); +} + +bool CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIStoreLinkKeyCommand() +{ + if (s_link_keys.empty()) + return false; + + const u8 type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE; + // The HCI command field is limited to uint8_t, and libusb to uint16_t. + const u8 payload_size = + static_cast(sizeof(hci_write_stored_link_key_cp)) + + (sizeof(btaddr_t) + sizeof(linkkey_t)) * static_cast(s_link_keys.size()); + std::vector packet(sizeof(hci_cmd_hdr_t) + payload_size); + + auto* header = reinterpret_cast(packet.data()); + header->opcode = HCI_CMD_WRITE_STORED_LINK_KEY; + header->length = payload_size; + + auto* cmd = + reinterpret_cast(packet.data() + sizeof(hci_cmd_hdr_t)); + cmd->num_keys_write = static_cast(s_link_keys.size()); + + // This is really ugly, but necessary because of the HCI command structure: + // u8 num_keys; + // u8 bdaddr[6]; + // u8 key[16]; + // where the two last items are repeated num_keys times. + auto iterator = packet.begin() + sizeof(hci_cmd_hdr_t) + sizeof(hci_write_stored_link_key_cp); + for (const auto& entry : s_link_keys) + { + std::copy(entry.first.begin(), entry.first.end(), iterator); + iterator += entry.first.size(); + std::copy(entry.second.begin(), entry.second.end(), iterator); + iterator += entry.second.size(); + } + + libusb_control_transfer(m_handle, type, 0, 0, 0, packet.data(), static_cast(packet.size()), + TIMEOUT); + return true; +} + // Due to how the widcomm stack which Nintendo uses is coded, we must never // let the stack think the controller is buffering more than 10 data packets // - it will cause a u8 underflow and royally screw things up. @@ -311,6 +423,59 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeSyncButtonHeldEvent(const Ctr m_sync_button_state = SyncButtonState::Ignored; } +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::LoadLinkKeys() +{ + const std::string& entries = SConfig::GetInstance().m_bt_passthrough_link_keys; + if (entries.empty()) + return; + std::vector pairs; + SplitString(entries, ',', pairs); + for (const auto& pair : pairs) + { + const auto index = pair.find('='); + if (index == std::string::npos) + continue; + + btaddr_t address; + StringToMacAddress(pair.substr(0, index), address.data()); + std::reverse(address.begin(), address.end()); + + const std::string& key_string = pair.substr(index + 1); + linkkey_t key; + size_t pos = 0; + for (size_t i = 0; i < key_string.length(); i = i + 2) + { + int value; + std::stringstream(key_string.substr(i, 2)) >> std::hex >> value; + key[pos++] = value; + } + + s_link_keys[address] = key; + } +} + +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SaveLinkKeys() +{ + std::ostringstream oss; + for (const auto& entry : s_link_keys) + { + btaddr_t address; + // Reverse the address so that it is stored in the correct order in the config file + std::reverse_copy(entry.first.begin(), entry.first.end(), address.begin()); + oss << MacAddressToString(address.data()); + oss << '='; + oss << std::hex; + for (const u16& data : entry.second) + oss << std::setfill('0') << std::setw(2) << data; + oss << std::dec << ','; + } + std::string config_string = oss.str(); + if (!config_string.empty()) + config_string.pop_back(); + SConfig::GetInstance().m_bt_passthrough_link_keys = config_string; + SConfig::GetInstance().SaveSettings(); +} + bool CWII_IPC_HLE_Device_usb_oh1_57e_305_real::OpenDevice(libusb_device* device) { m_device = libusb_ref_device(device); @@ -402,6 +567,29 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::TransferCallback(libusb_transfer* { s_showed_failed_transfer.Clear(); } + + if (tr->status == LIBUSB_TRANSFER_COMPLETED && tr->endpoint == HCI_EVENT) + { + const auto* event = reinterpret_cast(tr->buffer); + if (event->event == HCI_EVENT_LINK_KEY_NOTIFICATION) + { + const auto* notification = + reinterpret_cast(tr->buffer + sizeof(hci_event_hdr_t)); + + btaddr_t addr; + std::copy(std::begin(notification->bdaddr.b), std::end(notification->bdaddr.b), addr.begin()); + linkkey_t key; + std::copy(std::begin(notification->key), std::end(notification->key), std::begin(key)); + s_link_keys[addr] = key; + } + else if (event->event == HCI_EVENT_COMMAND_COMPL && + reinterpret_cast(tr->buffer + sizeof(*event))->opcode == + HCI_CMD_RESET) + { + s_need_reset_keys.Set(); + } + } + ctrl->SetRetVal(tr->actual_length); EnqueueReply(ctrl->m_cmd_address); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h index 2981896a39..b55e23ebc8 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h @@ -5,6 +5,7 @@ #pragma once #if defined(__LIBUSB__) +#include #include #include @@ -27,6 +28,9 @@ enum class SyncButtonState Ignored, }; +using btaddr_t = std::array; +using linkkey_t = std::array; + class CWII_IPC_HLE_Device_usb_oh1_57e_305_real final : public CWII_IPC_HLE_Device_usb_oh1_57e_305_base { @@ -67,12 +71,20 @@ private: // Set when we received a command to read the buffer size, and we need to fake a reply Common::Flag m_fake_read_buffer_size_reply; + bool m_is_wii_bt_module = false; + + void WaitForHCICommandComplete(u16 opcode); void SendHCIResetCommand(); + void SendHCIDeleteLinkKeyCommand(); + bool SendHCIStoreLinkKeyCommand(); void FakeReadBufferSizeReply(const CtrlBuffer& ctrl); void FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, u8 size); void FakeSyncButtonPressedEvent(const CtrlBuffer& ctrl); void FakeSyncButtonHeldEvent(const CtrlBuffer& ctrl); + void LoadLinkKeys(); + void SaveLinkKeys(); + bool OpenDevice(libusb_device* device); void StartTransferThread(); void StopTransferThread(); From b91095a9fc2a92e425eb4920206785e12dc251cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 27 Sep 2016 21:33:45 +0200 Subject: [PATCH 6/8] IPC_HLE/57e_305: Fake vendor-specific command replies Homebrew programs seem to rely on getting a reply to the vendor specific commands, without which Bluetooth initialisation will never complete. This vendor-specific command is typically used to patch the Wii's Bluetooth module, so the replies are only faked when the passed through adapter is not a Wii Bluetooth module. --- .../WII_IPC_HLE_Device_usb_bt_real.cpp | 23 +++++++++++++++++++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h | 5 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp index b6a5b5b8db..27bddc8361 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp @@ -171,6 +171,12 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad m_fake_read_buffer_size_reply.Set(); return GetNoReply(); } + if (!m_is_wii_bt_module && (opcode == 0xFC4C || opcode == 0xFC4F)) + { + m_fake_vendor_command_reply.Set(); + m_fake_vendor_command_reply_opcode = opcode; + return GetNoReply(); + } if (opcode == HCI_CMD_DELETE_STORED_LINK_KEY) { // Delete link key(s) from our own link key storage when the game tells the adapter to @@ -208,6 +214,11 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad FakeReadBufferSizeReply(*buffer); return GetNoReply(); } + if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && m_fake_vendor_command_reply.TestAndClear()) + { + FakeVendorCommandReply(*buffer); + return GetNoReply(); + } if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && m_sync_button_state == SyncButtonState::Pressed) { @@ -364,6 +375,18 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIStoreLinkKeyCommand() return true; } +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeVendorCommandReply(const CtrlBuffer& ctrl) +{ + u8* packet = Memory::GetPointer(ctrl.m_payload_addr); + auto* hci_event = reinterpret_cast(packet); + hci_event->EventType = HCI_EVENT_COMMAND_COMPL; + hci_event->PayloadLength = sizeof(SHCIEventCommand) - 2; + hci_event->PacketIndicator = 0x01; + hci_event->Opcode = m_fake_vendor_command_reply_opcode; + ctrl.SetRetVal(sizeof(SHCIEventCommand)); + EnqueueReply(ctrl.m_cmd_address); +} + // Due to how the widcomm stack which Nintendo uses is coded, we must never // let the stack think the controller is buffering more than 10 data packets // - it will cause a u8 underflow and royally screw things up. diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h index b55e23ebc8..3bab9db86b 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h @@ -68,8 +68,10 @@ private: Common::Flag m_thread_running; std::thread m_thread; - // Set when we received a command to read the buffer size, and we need to fake a reply + // Set when we received a command to which we need to fake a reply Common::Flag m_fake_read_buffer_size_reply; + Common::Flag m_fake_vendor_command_reply; + u16 m_fake_vendor_command_reply_opcode; bool m_is_wii_bt_module = false; @@ -77,6 +79,7 @@ private: void SendHCIResetCommand(); void SendHCIDeleteLinkKeyCommand(); bool SendHCIStoreLinkKeyCommand(); + void FakeVendorCommandReply(const CtrlBuffer& ctrl); void FakeReadBufferSizeReply(const CtrlBuffer& ctrl); void FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, u8 size); void FakeSyncButtonPressedEvent(const CtrlBuffer& ctrl); From 8912bb3ff4c60c4629539829a983885d44583585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 2 Oct 2016 16:59:41 +0200 Subject: [PATCH 7/8] Back up part of SYSCONF when switching to emulated BT This fixes an issue where the Bluetooth info section could be fully filled up by syncing 5 Wiimotes in passthrough mode then switching to emulated Bluetooth; emulated Wiimotes were then unable to be used. The "real" SYSCONF section is now backed up before being replaced with a blank section that the emulated BT adapter can always fill with 5 Wiimotes without issues. This backup is restored by the passthrough code, instead of during the Bluetooth mode switch because this should be done regardless of the user interface, and even without UI (if the config file is edited manually). --- Source/Core/Common/CommonPaths.h | 1 + Source/Core/Core/BootManager.cpp | 3 ++ .../WII_IPC_HLE_Device_usb_bt_base.cpp | 44 ++++++++++++++++++- .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h | 3 ++ .../IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp | 27 ++++-------- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index 24152773df..c6cc3e2acf 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -120,6 +120,7 @@ #define WII_STATE "state.dat" #define WII_SDCARD "sd.raw" +#define WII_BTDINF_BACKUP "btdinf.bak" #define WII_SETTING "setting.txt" diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 6758c25b48..732955cf5e 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -35,6 +35,7 @@ #include "Core/HW/Sram.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/Host.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" #include "VideoCommon/VideoBackendBase.h" @@ -399,6 +400,8 @@ bool BootCore(const std::string& _rFilename) // TODO: remove this if and once Dolphin supports WC24 standby mode. SConfig::GetInstance().m_SYSCONF->SetData("IPL.IDL", 0x00); NOTICE_LOG(BOOT, "Disabling WC24 'standby' (shutdown to idle) to avoid hanging on shutdown"); + + RestoreBTInfoSection(); } // Run the game diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp index 85e2095fa3..67884c7b8d 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.cpp @@ -2,14 +2,56 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" +#include +#include + #include "Common/Assert.h" #include "Common/CommonFuncs.h" +#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" +#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/Memmap.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h" + +constexpr u16 BT_INFO_SECTION_LENGTH = 0x460; + +void BackUpBTInfoSection() +{ + const std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_BTDINF_BACKUP; + if (File::Exists(filename)) + return; + File::IOFile backup(filename, "wb"); + std::vector section(BT_INFO_SECTION_LENGTH); + if (!SConfig::GetInstance().m_SYSCONF->GetArrayData("BT.DINF", section.data(), + static_cast(section.size()))) + { + ERROR_LOG(WII_IPC_WIIMOTE, "Failed to read source BT.DINF section"); + return; + } + if (!backup.WriteBytes(section.data(), section.size())) + ERROR_LOG(WII_IPC_WIIMOTE, "Failed to back up BT.DINF section"); +} + +void RestoreBTInfoSection() +{ + const std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_BTDINF_BACKUP; + if (!File::Exists(filename)) + return; + File::IOFile backup(filename, "rb"); + std::vector section(BT_INFO_SECTION_LENGTH); + if (!backup.ReadBytes(section.data(), section.size())) + { + ERROR_LOG(WII_IPC_WIIMOTE, "Failed to read backed up BT.DINF section"); + return; + } + SConfig::GetInstance().m_SYSCONF->SetArrayData("BT.DINF", section.data(), + static_cast(section.size())); + SConfig::GetInstance().m_SYSCONF->Save(); + File::Delete(filename); +} IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_base::IOCtl(u32 command_address) { diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h index dee774905b..ea28ad17b9 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h @@ -7,6 +7,9 @@ #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" +void BackUpBTInfoSection(); +void RestoreBTInfoSection(); + class CWII_IPC_HLE_Device_usb_oh1_57e_305_base : public IWII_IPC_HLE_Device { public: diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp index 58772cde85..d672464cf4 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp @@ -46,6 +46,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CWII_IPC_HLE_Device_usb_oh1_57e_305_emu else { sysconf = SConfig::GetInstance().m_SYSCONF; + BackUpBTInfoSection(); } // Activate only first Wiimote by default @@ -62,24 +63,13 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CWII_IPC_HLE_Device_usb_oh1_57e_305_emu u8 i = 0; while (i < MAX_BBMOTES) { - if (i < BT_DINF.num_registered) - { - tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0]; - tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1]; - tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2]; - tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3]; - tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4]; - tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5]; - } - else - { - tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0] = i; - tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1] = 0; - tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2] = 0x79; - tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3] = 0x19; - tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4] = 2; - tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5] = 0x11; - } + // Previous records can be safely overwritten, since they are backed up + tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0] = i; + tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1] = 0; + tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2] = 0x79; + tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3] = 0x19; + tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4] = 2; + tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5] = 0x11; const char* wmName; if (i == WIIMOTE_BALANCE_BOARD) @@ -95,6 +85,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CWII_IPC_HLE_Device_usb_oh1_57e_305_emu i++; } + BT_DINF.num_registered = MAX_BBMOTES; // save now so that when games load sysconf file it includes the new Wiimotes // and the correct order for connected Wiimotes if (!sysconf->SetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)) || !sysconf->Save()) From 6ff06ed41d49971859036999b8892c7a6c862dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 3 Oct 2016 01:08:50 +0200 Subject: [PATCH 8/8] WII_IPC_HLE: Clean up variable naming It doesn't make much sense to prefix g_ to static variables and for some to be completely unprefixed. Also renames a lot of other variables for the new conventions --- Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp | 289 +++++++++++------------ Source/Core/Core/IPC_HLE/WII_IPC_HLE.h | 1 - 2 files changed, 144 insertions(+), 146 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index 2cd0c130ac..3799113178 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -64,42 +64,41 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC namespace WII_IPC_HLE_Interface { -typedef std::map> TDeviceMap; -static TDeviceMap g_DeviceMap; -static std::mutex g_device_map_mutex; +static std::map> s_device_map; +static std::mutex s_device_map_mutex; // STATE_TO_SAVE #define IPC_MAX_FDS 0x18 #define ES_MAX_COUNT 2 -static std::shared_ptr g_FdMap[IPC_MAX_FDS]; -static bool es_inuse[ES_MAX_COUNT]; -static std::shared_ptr es_handles[ES_MAX_COUNT]; +static std::shared_ptr s_fdmap[IPC_MAX_FDS]; +static bool s_es_inuse[ES_MAX_COUNT]; +static std::shared_ptr s_es_handles[ES_MAX_COUNT]; -typedef std::deque ipc_msg_queue; -static ipc_msg_queue request_queue; // ppc -> arm -static ipc_msg_queue reply_queue; // arm -> ppc -static ipc_msg_queue ack_queue; // arm -> ppc +using IPCMsgQueue = std::deque; +static IPCMsgQueue s_request_queue; // ppc -> arm +static IPCMsgQueue s_reply_queue; // arm -> ppc +static IPCMsgQueue s_ack_queue; // arm -> ppc -static CoreTiming::EventType* event_enqueue; -static CoreTiming::EventType* event_sdio_notify; +static CoreTiming::EventType* s_event_enqueue; +static CoreTiming::EventType* s_event_sdio_notify; -static u64 last_reply_time; +static u64 s_last_reply_time; -static const u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; -static const u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; +static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; +static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; static void EnqueueEvent(u64 userdata, s64 cycles_late = 0) { if (userdata & ENQUEUE_ACKNOWLEDGEMENT_FLAG) { - ack_queue.push_back((u32)userdata); + s_ack_queue.push_back(static_cast(userdata)); } else if (userdata & ENQUEUE_REQUEST_FLAG) { - request_queue.push_back((u32)userdata); + s_request_queue.push_back(static_cast(userdata)); } else { - reply_queue.push_back((u32)userdata); + s_reply_queue.push_back(static_cast(userdata)); } Update(); } @@ -115,18 +114,18 @@ static void SDIO_EventNotify_CPUThread(u64 userdata, s64 cycles_late) static u32 num_devices; template -std::shared_ptr AddDevice(const char* deviceName) +std::shared_ptr AddDevice(const char* device_name) { - auto device = std::make_shared(num_devices, deviceName); - g_DeviceMap[num_devices] = device; + auto device = std::make_shared(num_devices, device_name); + s_device_map[num_devices] = device; num_devices++; return device; } void Reinit() { - std::lock_guard lock(g_device_map_mutex); - _assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "Reinit called while already initialized"); + std::lock_guard lock(s_device_map_mutex); + _assert_msg_(WII_IPC_HLE, s_device_map.empty(), "Reinit called while already initialized"); CWII_IPC_HLE_Device_es::m_ContentFile = ""; num_devices = 0; @@ -144,8 +143,8 @@ void Reinit() // IOS allows two ES devices at a time for (u32 j = 0; j < ES_MAX_COUNT; j++) { - es_handles[j] = AddDevice("/dev/es"); - es_inuse[j] = false; + s_es_handles[j] = AddDevice("/dev/es"); + s_es_inuse[j] = false; } AddDevice("/dev/di"); @@ -172,15 +171,15 @@ void Init() { Reinit(); - event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); - event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread); + s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); + s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread); } -void Reset(bool _bHard) +void Reset(bool hard) { - CoreTiming::RemoveAllEvents(event_enqueue); + CoreTiming::RemoveAllEvents(s_event_enqueue); - for (auto& dev : g_FdMap) + for (auto& dev : s_fdmap) { if (dev && !dev->IsHardware()) { @@ -191,14 +190,14 @@ void Reset(bool _bHard) dev.reset(); } - for (bool& in_use : es_inuse) + for (bool& in_use : s_es_inuse) { in_use = false; } { - std::lock_guard lock(g_device_map_mutex); - for (const auto& entry : g_DeviceMap) + std::lock_guard lock(s_device_map_mutex); + for (const auto& entry : s_device_map) { if (entry.second) { @@ -207,14 +206,14 @@ void Reset(bool _bHard) } } - if (_bHard) - g_DeviceMap.clear(); + if (hard) + s_device_map.clear(); } - request_queue.clear(); - reply_queue.clear(); + s_request_queue.clear(); + s_reply_queue.clear(); - last_reply_time = 0; + s_last_reply_time = 0; } void Shutdown() @@ -222,14 +221,14 @@ void Shutdown() Reset(true); } -void SetDefaultContentFile(const std::string& _rFilename) +void SetDefaultContentFile(const std::string& file_name) { - std::lock_guard lock(g_device_map_mutex); - for (const auto& entry : g_DeviceMap) + std::lock_guard lock(s_device_map_mutex); + for (const auto& entry : s_device_map) { if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0) { - static_cast(entry.second.get())->LoadWAD(_rFilename); + static_cast(entry.second.get())->LoadWAD(file_name); } } } @@ -244,14 +243,14 @@ void SDIO_EventNotify() // TODO: Potential race condition: If IsRunning() becomes false after // it's checked, an event may be scheduled after CoreTiming shuts down. if (SConfig::GetInstance().bWii && Core::IsRunning()) - CoreTiming::ScheduleEvent(0, event_sdio_notify, 0, CoreTiming::FromThread::NON_CPU); + CoreTiming::ScheduleEvent(0, s_event_sdio_notify, 0, CoreTiming::FromThread::NON_CPU); } -int getFreeDeviceId() +static int GetFreeDeviceID() { for (u32 i = 0; i < IPC_MAX_FDS; i++) { - if (g_FdMap[i] == nullptr) + if (s_fdmap[i] == nullptr) { return i; } @@ -260,12 +259,12 @@ int getFreeDeviceId() return -1; } -std::shared_ptr GetDeviceByName(const std::string& _rDeviceName) +std::shared_ptr GetDeviceByName(const std::string& device_name) { - std::lock_guard lock(g_device_map_mutex); - for (const auto& entry : g_DeviceMap) + std::lock_guard lock(s_device_map_mutex); + for (const auto& entry : s_device_map) { - if (entry.second && entry.second->GetDeviceName() == _rDeviceName) + if (entry.second && entry.second->GetDeviceName() == device_name) { return entry.second; } @@ -274,40 +273,40 @@ std::shared_ptr GetDeviceByName(const std::string& _rDevice return nullptr; } -std::shared_ptr AccessDeviceByID(u32 _ID) +std::shared_ptr AccessDeviceByID(u32 id) { - std::lock_guard lock(g_device_map_mutex); - if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) + std::lock_guard lock(s_device_map_mutex); + if (s_device_map.find(id) != s_device_map.end()) { - return g_DeviceMap[_ID]; + return s_device_map[id]; } return nullptr; } // This is called from ExecuteCommand() COMMAND_OPEN_DEVICE -std::shared_ptr CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName) +std::shared_ptr CreateFileIO(u32 device_id, const std::string& device_name) { // scan device name and create the right one - INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str()); - return std::make_shared(_DeviceID, _rDeviceName); + INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", device_name.c_str()); + return std::make_shared(device_id, device_name); } void DoState(PointerWrap& p) { - p.Do(request_queue); - p.Do(reply_queue); - p.Do(last_reply_time); + p.Do(s_request_queue); + p.Do(s_reply_queue); + p.Do(s_last_reply_time); // We need to make sure all file handles are closed so WII_IPC_Devices_fs::DoState can // successfully save or re-create /tmp - for (auto& descriptor : g_FdMap) + for (auto& descriptor : s_fdmap) { if (descriptor) descriptor->PrepareForState(p.GetMode()); } - for (const auto& entry : g_DeviceMap) + for (const auto& entry : s_device_map) { if (entry.second->IsHardware()) { @@ -329,28 +328,28 @@ void DoState(PointerWrap& p) { u32 hwId = 0; p.Do(hwId); - g_FdMap[i] = AccessDeviceByID(hwId); + s_fdmap[i] = AccessDeviceByID(hwId); } else { - g_FdMap[i] = std::make_shared(i, ""); - g_FdMap[i]->DoState(p); + s_fdmap[i] = std::make_shared(i, ""); + s_fdmap[i]->DoState(p); } } } for (u32 i = 0; i < ES_MAX_COUNT; i++) { - p.Do(es_inuse[i]); - u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(s_es_inuse[i]); + u32 handleID = s_es_handles[i]->GetDeviceID(); p.Do(handleID); - es_handles[i] = AccessDeviceByID(handleID); + s_es_handles[i] = AccessDeviceByID(handleID); } } else { - for (auto& descriptor : g_FdMap) + for (auto& descriptor : s_fdmap) { u32 exists = descriptor ? 1 : 0; p.Do(exists); @@ -372,203 +371,203 @@ void DoState(PointerWrap& p) for (u32 i = 0; i < ES_MAX_COUNT; i++) { - p.Do(es_inuse[i]); - u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(s_es_inuse[i]); + u32 handleID = s_es_handles[i]->GetDeviceID(); p.Do(handleID); } } } -void ExecuteCommand(u32 _Address) +void ExecuteCommand(u32 address) { IPCCommandResult result = IWII_IPC_HLE_Device::GetNoReply(); - IPCCommandType Command = static_cast(Memory::Read_U32(_Address)); - s32 DeviceID = Memory::Read_U32(_Address + 8); + IPCCommandType Command = static_cast(Memory::Read_U32(address)); + s32 DeviceID = Memory::Read_U32(address + 8); - std::shared_ptr pDevice = - (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr; + std::shared_ptr device = + (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? s_fdmap[DeviceID] : nullptr; - DEBUG_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, - Command, DeviceID, pDevice.get()); + DEBUG_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", address, + Command, DeviceID, device.get()); switch (Command) { case IPC_CMD_OPEN: { - u32 Mode = Memory::Read_U32(_Address + 0x10); - DeviceID = getFreeDeviceId(); + u32 Mode = Memory::Read_U32(address + 0x10); + DeviceID = GetFreeDeviceID(); - std::string DeviceName = Memory::GetString(Memory::Read_U32(_Address + 0xC)); + std::string device_name = Memory::GetString(Memory::Read_U32(address + 0xC)); - INFO_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID); + INFO_LOG(WII_IPC_HLE, "Trying to open %s as %d", device_name.c_str(), DeviceID); if (DeviceID >= 0) { - if (DeviceName.find("/dev/es") == 0) + if (device_name.find("/dev/es") == 0) { u32 j; for (j = 0; j < ES_MAX_COUNT; j++) { - if (!es_inuse[j]) + if (!s_es_inuse[j]) { - es_inuse[j] = true; - g_FdMap[DeviceID] = es_handles[j]; - result = es_handles[j]->Open(_Address, Mode); - Memory::Write_U32(DeviceID, _Address + 4); + s_es_inuse[j] = true; + s_fdmap[DeviceID] = s_es_handles[j]; + result = s_es_handles[j]->Open(address, Mode); + Memory::Write_U32(DeviceID, address + 4); break; } } if (j == ES_MAX_COUNT) { - Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4); + Memory::Write_U32(FS_EESEXHAUSTED, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } } - else if (DeviceName.find("/dev/") == 0) + else if (device_name.find("/dev/") == 0) { - pDevice = GetDeviceByName(DeviceName); - if (pDevice) + device = GetDeviceByName(device_name); + if (device) { - g_FdMap[DeviceID] = pDevice; - result = pDevice->Open(_Address, Mode); + s_fdmap[DeviceID] = device; + result = device->Open(address, Mode); DEBUG_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), DeviceID, Mode); - Memory::Write_U32(DeviceID, _Address + 4); + device->GetDeviceName().c_str(), DeviceID, Mode); + Memory::Write_U32(DeviceID, address + 4); } else { - WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str()); - Memory::Write_U32(FS_ENOENT, _Address + 4); + WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", device_name.c_str()); + Memory::Write_U32(FS_ENOENT, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } } else { - pDevice = CreateFileIO(DeviceID, DeviceName); - result = pDevice->Open(_Address, Mode); + device = CreateFileIO(DeviceID, device_name); + result = device->Open(address, Mode); DEBUG_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), DeviceID, Mode); - if (Memory::Read_U32(_Address + 4) == (u32)DeviceID) + device->GetDeviceName().c_str(), DeviceID, Mode); + if (Memory::Read_U32(address + 4) == (u32)DeviceID) { - g_FdMap[DeviceID] = pDevice; + s_fdmap[DeviceID] = device; } } } else { - Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4); + Memory::Write_U32(FS_EFDEXHAUSTED, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } break; } case IPC_CMD_CLOSE: { - if (pDevice) + if (device) { - result = pDevice->Close(_Address); + result = device->Close(address); for (u32 j = 0; j < ES_MAX_COUNT; j++) { - if (es_handles[j] == g_FdMap[DeviceID]) + if (s_es_handles[j] == s_fdmap[DeviceID]) { - es_inuse[j] = false; + s_es_inuse[j] = false; } } - g_FdMap[DeviceID].reset(); + s_fdmap[DeviceID].reset(); } else { - Memory::Write_U32(FS_EINVAL, _Address + 4); + Memory::Write_U32(FS_EINVAL, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } break; } case IPC_CMD_READ: { - if (pDevice) + if (device) { - result = pDevice->Read(_Address); + result = device->Read(address); } else { - Memory::Write_U32(FS_EINVAL, _Address + 4); + Memory::Write_U32(FS_EINVAL, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } break; } case IPC_CMD_WRITE: { - if (pDevice) + if (device) { - result = pDevice->Write(_Address); + result = device->Write(address); } else { - Memory::Write_U32(FS_EINVAL, _Address + 4); + Memory::Write_U32(FS_EINVAL, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } break; } case IPC_CMD_SEEK: { - if (pDevice) + if (device) { - result = pDevice->Seek(_Address); + result = device->Seek(address); } else { - Memory::Write_U32(FS_EINVAL, _Address + 4); + Memory::Write_U32(FS_EINVAL, address + 4); result = IWII_IPC_HLE_Device::GetDefaultReply(); } break; } case IPC_CMD_IOCTL: { - if (pDevice) + if (device) { - result = pDevice->IOCtl(_Address); + result = device->IOCtl(address); } break; } case IPC_CMD_IOCTLV: { - if (pDevice) + if (device) { - result = pDevice->IOCtlV(_Address); + result = device->IOCtlV(address); } break; } default: { - _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address); + _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, address); break; } } // Ensure replies happen in order - const s64 ticks_until_last_reply = last_reply_time - CoreTiming::GetTicks(); + const s64 ticks_until_last_reply = s_last_reply_time - CoreTiming::GetTicks(); if (ticks_until_last_reply > 0) result.reply_delay_ticks += ticks_until_last_reply; - last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks; + s_last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks; if (result.send_reply) { // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, _Address); + Memory::Write_U32(IPC_REP_ASYNC, address); // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(Command, _Address + 8); + Memory::Write_U32(Command, address + 8); // Generate a reply to the IPC command - EnqueueReply(_Address, (int)result.reply_delay_ticks); + EnqueueReply(address, (int)result.reply_delay_ticks); } } // Happens AS SOON AS IPC gets a new pointer! void EnqueueRequest(u32 address) { - CoreTiming::ScheduleEvent(1000, event_enqueue, address | ENQUEUE_REQUEST_FLAG); + CoreTiming::ScheduleEvent(1000, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG); } // Called when IOS module has some reply @@ -577,12 +576,12 @@ void EnqueueRequest(u32 address) // Please search for examples of this being called elsewhere. void EnqueueReply(u32 address, int cycles_in_future, CoreTiming::FromThread from) { - CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, address, from); + CoreTiming::ScheduleEvent(cycles_in_future, s_event_enqueue, address, from); } void EnqueueCommandAcknowledgement(u32 address, int cycles_in_future) { - CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, + CoreTiming::ScheduleEvent(cycles_in_future, s_event_enqueue, address | ENQUEUE_ACKNOWLEDGEMENT_FLAG); } @@ -593,29 +592,29 @@ void Update() if (!WII_IPCInterface::IsReady()) return; - if (request_queue.size()) + if (s_request_queue.size()) { - WII_IPCInterface::GenerateAck(request_queue.front()); - DEBUG_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front()); - u32 command = request_queue.front(); - request_queue.pop_front(); + WII_IPCInterface::GenerateAck(s_request_queue.front()); + DEBUG_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", s_request_queue.front()); + u32 command = s_request_queue.front(); + s_request_queue.pop_front(); ExecuteCommand(command); return; } - if (reply_queue.size()) + if (s_reply_queue.size()) { - WII_IPCInterface::GenerateReply(reply_queue.front()); - DEBUG_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front()); - reply_queue.pop_front(); + WII_IPCInterface::GenerateReply(s_reply_queue.front()); + DEBUG_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", s_reply_queue.front()); + s_reply_queue.pop_front(); return; } - if (ack_queue.size()) + if (s_ack_queue.size()) { - WII_IPCInterface::GenerateAck(ack_queue.front()); - WARN_LOG(WII_IPC_HLE, "<<-- Double-ack to IPC Request @ 0x%08x", ack_queue.front()); - ack_queue.pop_front(); + WII_IPCInterface::GenerateAck(s_ack_queue.front()); + WARN_LOG(WII_IPC_HLE, "<<-- Double-ack to IPC Request @ 0x%08x", s_ack_queue.front()); + s_ack_queue.pop_front(); return; } } @@ -623,7 +622,7 @@ void Update() void UpdateDevices() { // Check if a hardware device must be updated - for (const auto& entry : g_DeviceMap) + for (const auto& entry : s_device_map) { if (entry.second->IsOpened()) { diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h index 4ec90fac6f..d0a274349b 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h @@ -67,7 +67,6 @@ std::shared_ptr CreateFileIO(u32 _DeviceID, const std::stri std::shared_ptr GetDeviceByName(const std::string& _rDeviceName); std::shared_ptr AccessDeviceByID(u32 _ID); -int getFreeDeviceId(); // Update void Update();