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] 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);