mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Add ability to passthrough a Bluetooth adapter
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).
This commit is contained in:
@@ -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})
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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() ?
|
||||
|
||||
@@ -185,7 +185,12 @@
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_net_ssl.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_stm.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_sdio_slot0.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_base.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_emu.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_real.cpp">
|
||||
<DisableSpecificWarnings>4200;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_stub.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_kbd.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_ven.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_WiiMote.cpp" />
|
||||
@@ -389,7 +394,10 @@
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_net_ssl.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_stm.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_sdio_slot0.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_base.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_emu.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_real.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_stub.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_kbd.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_ven.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_WiiMote.h" />
|
||||
|
||||
@@ -591,7 +591,16 @@
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_hid.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb.cpp">
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_base.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_emu.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_real.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_stub.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_WiiMote.cpp">
|
||||
@@ -1148,7 +1157,16 @@
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_hid.h">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb.h">
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_base.h">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_emu.h">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_real.h">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_bt_stub.h">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB/BT/Wiimote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_WiiMote.h">
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -31,6 +31,7 @@ enum Hotkey
|
||||
HK_SCREENSHOT,
|
||||
HK_EXIT,
|
||||
|
||||
HK_TRIGGER_SYNC_BUTTON,
|
||||
HK_WIIMOTE1_CONNECT,
|
||||
HK_WIIMOTE2_CONNECT,
|
||||
HK_WIIMOTE3_CONNECT,
|
||||
|
||||
@@ -22,6 +22,7 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -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<u32, std::shared_ptr<IWII_IPC_HLE_Device>> 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<T> AddDevice(const char* deviceName)
|
||||
|
||||
void Reinit()
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<CWII_IPC_HLE_Device_usb_oh1_57e_305>("/dev/usb/oh1/57e/305");
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
AddDevice<CWII_IPC_HLE_Device_usb_oh1_57e_305_emu>("/dev/usb/oh1/57e/305");
|
||||
else
|
||||
AddDevice<CWII_IPC_HLE_Device_usb_oh1_57e_305_real>("/dev/usb/oh1/57e/305");
|
||||
|
||||
AddDevice<CWII_IPC_HLE_Device_stm_immediate>("/dev/stm/immediate");
|
||||
AddDevice<CWII_IPC_HLE_Device_stm_eventhook>("/dev/stm/eventhook");
|
||||
AddDevice<CWII_IPC_HLE_Device_fs>("/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<std::mutex> 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<std::mutex> 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<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDeviceName)
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDevice
|
||||
|
||||
std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 _ID)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_device_map_mutex);
|
||||
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
||||
{
|
||||
return g_DeviceMap[_ID];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
+125
-119
File diff suppressed because it is too large
Load Diff
+10
-51
@@ -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<CWII_IPC_HLE_WiiMote> 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);
|
||||
@@ -0,0 +1,370 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#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<CtrlMessage>(cmd_buffer);
|
||||
auto buffer = std::vector<u8>(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<CtrlBuffer>(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<hci_event_hdr_t*>(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<CtrlMessage> cmd(static_cast<CtrlMessage*>(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<CtrlBuffer> ctrl(static_cast<CtrlBuffer*>(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);
|
||||
}
|
||||
@@ -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 <atomic>
|
||||
#include <thread>
|
||||
|
||||
#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<SyncButtonState> 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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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; }
|
||||
};
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user