mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #13791 from jordan-woyak/realtek-firmware-loader
BTReal: Implement Realtek firmware loading.
This commit is contained in:
@@ -7,11 +7,13 @@
|
||||
#include <bit>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
///
|
||||
@@ -240,4 +242,19 @@ T ExpandValue(T value, size_t left_shift_amount)
|
||||
return (value << left_shift_amount) |
|
||||
(T(-ExtractBit<0>(value)) >> (BitSize<T>() - left_shift_amount));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_trivially_copyable_v<T>)
|
||||
constexpr auto AsU8Span(const T& obj)
|
||||
{
|
||||
return std::span{reinterpret_cast<const u8*>(std::addressof(obj)), sizeof(obj)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_trivially_copyable_v<T>)
|
||||
constexpr auto AsWritableU8Span(T& obj)
|
||||
{
|
||||
return std::span{reinterpret_cast<u8*>(std::addressof(obj)), sizeof(obj)};
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
#define RESOURCEPACK_DIR "ResourcePacks"
|
||||
#define DYNAMICINPUT_DIR "DynamicInputTextures"
|
||||
#define GRAPHICSMOD_DIR "GraphicMods"
|
||||
#define FIRMWARE_DIR "Firmware"
|
||||
#define WIISDSYNC_DIR "WiiSDSync"
|
||||
#define ASSEMBLY_DIR "SavedAssembly"
|
||||
#define WIIBANNERS_DIR "WiiBanners"
|
||||
|
||||
@@ -882,6 +882,7 @@ static void RebuildUserDirectories(unsigned int dir_index)
|
||||
s_user_paths[D_DYNAMICINPUT_IDX] = s_user_paths[D_LOAD_IDX] + DYNAMICINPUT_DIR DIR_SEP;
|
||||
s_user_paths[D_GRAPHICSMOD_IDX] = s_user_paths[D_LOAD_IDX] + GRAPHICSMOD_DIR DIR_SEP;
|
||||
s_user_paths[D_BANNERS_WIIROOT_IDX] = s_user_paths[D_LOAD_IDX] + WIIBANNERS_DIR DIR_SEP;
|
||||
s_user_paths[D_FIRMWARE_IDX] = s_user_paths[D_LOAD_IDX] + FIRMWARE_DIR DIR_SEP;
|
||||
s_user_paths[D_WIISDCARDSYNCFOLDER_IDX] = s_user_paths[D_LOAD_IDX] + WIISDSYNC_DIR DIR_SEP;
|
||||
s_user_paths[F_DOLPHINCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
|
||||
s_user_paths[F_GCPADCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + GCPAD_CONFIG;
|
||||
|
||||
@@ -68,6 +68,7 @@ enum
|
||||
D_RESOURCEPACK_IDX,
|
||||
D_DYNAMICINPUT_IDX,
|
||||
D_GRAPHICSMOD_IDX,
|
||||
D_FIRMWARE_IDX,
|
||||
D_GBAUSER_IDX,
|
||||
D_GBASAVES_IDX,
|
||||
D_WIISDCARDSYNCFOLDER_IDX,
|
||||
|
||||
@@ -699,6 +699,8 @@ if(TARGET LibUSB::LibUSB)
|
||||
IOS/USB/Bluetooth/BTReal.h
|
||||
IOS/USB/Bluetooth/LibUSBBluetoothAdapter.cpp
|
||||
IOS/USB/Bluetooth/LibUSBBluetoothAdapter.h
|
||||
IOS/USB/Bluetooth/RealtekFirmwareLoader.cpp
|
||||
IOS/USB/Bluetooth/RealtekFirmwareLoader.h
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/Network.h"
|
||||
#include "Common/StringUtil.h"
|
||||
@@ -27,24 +28,6 @@
|
||||
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <u16 Opcode, typename CommandType>
|
||||
struct HCICommandPayload
|
||||
{
|
||||
hci_cmd_hdr_t header{Opcode, sizeof(CommandType)};
|
||||
CommandType command{};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_trivially_copyable_v<T>)
|
||||
constexpr auto AsU8Span(const T& obj)
|
||||
{
|
||||
return std::span{reinterpret_cast<const u8*>(std::addressof(obj)), sizeof(obj)};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace IOS::HLE
|
||||
{
|
||||
|
||||
@@ -295,7 +278,7 @@ auto BluetoothRealDevice::ProcessHCIEvent(BufferType buffer) -> BufferType
|
||||
payload.command.latency = 10000;
|
||||
payload.command.delay_variation = 0xffffffff;
|
||||
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(AsU8Span(payload));
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(Common::AsU8Span(payload));
|
||||
}
|
||||
else if (event == HCI_EVENT_QOS_SETUP_COMPL)
|
||||
{
|
||||
@@ -402,7 +385,7 @@ void BluetoothRealDevice::TriggerSyncButtonHeldEvent()
|
||||
void BluetoothRealDevice::SendHCIResetCommand()
|
||||
{
|
||||
INFO_LOG_FMT(IOS_WIIMOTE, "SendHCIResetCommand");
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(AsU8Span(hci_cmd_hdr_t{HCI_CMD_RESET, 0}));
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(Common::AsU8Span(hci_cmd_hdr_t{HCI_CMD_RESET, 0}));
|
||||
}
|
||||
|
||||
void BluetoothRealDevice::SendHCIDeleteLinkKeyCommand()
|
||||
@@ -413,7 +396,7 @@ void BluetoothRealDevice::SendHCIDeleteLinkKeyCommand()
|
||||
payload.command.bdaddr = {};
|
||||
payload.command.delete_all = 0x01;
|
||||
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(AsU8Span(payload));
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(Common::AsU8Span(payload));
|
||||
}
|
||||
|
||||
bool BluetoothRealDevice::SendHCIStoreLinkKeyCommand()
|
||||
@@ -450,7 +433,7 @@ bool BluetoothRealDevice::SendHCIStoreLinkKeyCommand()
|
||||
for (auto& [bdaddr, linkkey] : m_link_keys | std::views::take(num_link_keys))
|
||||
payload.link_keys[index++] = {bdaddr, linkkey};
|
||||
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(AsU8Span(payload).first(payload_size));
|
||||
m_lib_usb_bt_adapter->SendControlTransfer(Common::AsU8Span(payload).first(payload_size));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
#include <fmt/format.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/IOS/USB/Bluetooth/RealtekFirmwareLoader.h"
|
||||
#include "Core/IOS/USB/Bluetooth/hci.h"
|
||||
|
||||
namespace
|
||||
@@ -53,13 +55,20 @@ bool LibUSBBluetoothAdapter::IsBluetoothDevice(const libusb_device_descriptor& d
|
||||
|
||||
// Some devices misreport their class, so we avoid relying solely on descriptor checks and allow
|
||||
// users to specify their own VID/PID.
|
||||
return is_bluetooth_protocol || LibUSBBluetoothAdapter::IsConfiguredBluetoothDevice(
|
||||
descriptor.idVendor, descriptor.idProduct);
|
||||
return is_bluetooth_protocol ||
|
||||
LibUSBBluetoothAdapter::IsConfiguredBluetoothDevice(descriptor.idVendor,
|
||||
descriptor.idProduct) ||
|
||||
IsKnownRealtekBluetoothDevice(descriptor.idVendor, descriptor.idProduct);
|
||||
}
|
||||
|
||||
bool LibUSBBluetoothAdapter::IsWiiBTModule() const
|
||||
{
|
||||
return m_is_wii_bt_module;
|
||||
return m_device_vid == 0x57e && m_device_pid == 0x305;
|
||||
}
|
||||
|
||||
bool LibUSBBluetoothAdapter::AreCommandsPendingResponse() const
|
||||
{
|
||||
return !m_pending_hci_transfers.empty() || !m_unacknowledged_commands.empty();
|
||||
}
|
||||
|
||||
bool LibUSBBluetoothAdapter::HasConfiguredBluetoothDevice()
|
||||
@@ -115,8 +124,9 @@ LibUSBBluetoothAdapter::LibUSBBluetoothAdapter()
|
||||
NOTICE_LOG_FMT(IOS_WIIMOTE, "Using device {:04x}:{:04x} (rev {:x}) for Bluetooth: {} {} {}",
|
||||
device_descriptor.idVendor, device_descriptor.idProduct,
|
||||
device_descriptor.bcdDevice, manufacturer, product, serial_number);
|
||||
m_is_wii_bt_module =
|
||||
device_descriptor.idVendor == 0x57e && device_descriptor.idProduct == 0x305;
|
||||
|
||||
m_device_vid = device_descriptor.idVendor;
|
||||
m_device_pid = device_descriptor.idProduct;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -151,6 +161,17 @@ LibUSBBluetoothAdapter::LibUSBBluetoothAdapter()
|
||||
|
||||
m_output_worker.Reset("Bluetooth Output",
|
||||
std::bind_front(&LibUSBBluetoothAdapter::SubmitTimedTransfer, this));
|
||||
|
||||
if (IsRealtekVID(m_device_vid) || IsKnownRealtekBluetoothDevice(m_device_vid, m_device_pid))
|
||||
{
|
||||
INFO_LOG_FMT(IOS_WIIMOTE, "Initializing Realtek Bluetooth device: {:04x}:{:04x}", m_device_vid,
|
||||
m_device_pid);
|
||||
if (!InitializeRealtekBluetoothDevice(*this))
|
||||
{
|
||||
PanicAlertFmtT("Failed to initialize Realtek Bluetooth device.\n\n"
|
||||
"Bluetooth passthrough will probably not work.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LibUSBBluetoothAdapter::~LibUSBBluetoothAdapter()
|
||||
@@ -159,7 +180,7 @@ LibUSBBluetoothAdapter::~LibUSBBluetoothAdapter()
|
||||
return;
|
||||
|
||||
// Wait for completion (or time out) of all HCI commands.
|
||||
while (!m_pending_hci_transfers.empty() && !m_unacknowledged_commands.empty())
|
||||
while (AreCommandsPendingResponse())
|
||||
{
|
||||
(void)ReceiveHCIEvent();
|
||||
Common::YieldCPU();
|
||||
@@ -394,6 +415,50 @@ void LibUSBBluetoothAdapter::SendControlTransfer(std::span<const u8> data)
|
||||
ScheduleControlTransfer(REQUEST_TYPE, 0, 0, 0, data, Clock::now());
|
||||
}
|
||||
|
||||
bool LibUSBBluetoothAdapter::SendBlockingCommand(std::span<const u8> data, std::span<u8> response)
|
||||
{
|
||||
SendControlTransfer(data);
|
||||
|
||||
const hci_cmd_hdr_t cmd = Common::BitCastPtr<hci_cmd_hdr_t>(data.data());
|
||||
|
||||
while (AreCommandsPendingResponse())
|
||||
{
|
||||
const auto event = ReceiveHCIEvent();
|
||||
|
||||
if (event.empty())
|
||||
{
|
||||
Common::YieldCPU();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event[0] != HCI_EVENT_COMMAND_COMPL)
|
||||
continue;
|
||||
|
||||
if (event.size() < sizeof(hci_event_hdr_t) + sizeof(hci_command_compl_ep))
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_WIIMOTE, "Undersized hci_command_compl_ep");
|
||||
continue;
|
||||
}
|
||||
|
||||
const hci_command_compl_ep compl_event =
|
||||
Common::BitCastPtr<hci_command_compl_ep>(event.data() + sizeof(hci_event_hdr_t));
|
||||
if (compl_event.opcode != cmd.opcode)
|
||||
continue;
|
||||
|
||||
if (event.size() < sizeof(hci_event_hdr_t) + sizeof(hci_command_compl_ep) + response.size())
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_WIIMOTE, "Undersized command result");
|
||||
break;
|
||||
}
|
||||
|
||||
std::copy_n(event.data() + sizeof(hci_event_hdr_t) + sizeof(hci_command_compl_ep),
|
||||
response.size(), response.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LibUSBBluetoothAdapter::StartInputTransfers()
|
||||
{
|
||||
constexpr auto callback = LibUSBMemFunCallback<&LibUSBBluetoothAdapter::HandleInputTransfer>();
|
||||
|
||||
@@ -12,12 +12,20 @@
|
||||
#include "Common/Timer.h"
|
||||
#include "Common/WorkQueueThread.h"
|
||||
|
||||
#include "Core/IOS/USB/Bluetooth/hci.h"
|
||||
#include "Core/LibusbUtils.h"
|
||||
|
||||
struct libusb_device_handle;
|
||||
struct libusb_device_descriptor;
|
||||
struct libusb_transfer;
|
||||
|
||||
template <u16 Opcode, typename CommandType>
|
||||
struct HCICommandPayload
|
||||
{
|
||||
hci_cmd_hdr_t header{Opcode, sizeof(CommandType)};
|
||||
CommandType command{};
|
||||
};
|
||||
|
||||
class LibUSBBluetoothAdapter
|
||||
{
|
||||
public:
|
||||
@@ -45,6 +53,11 @@ public:
|
||||
// Schedule a transfer to be submitted as soon as possible.
|
||||
void SendControlTransfer(std::span<const u8> data);
|
||||
|
||||
// Blocks and eats events until a command complete event of the correct opcode is received.
|
||||
// Returns true on success or false on error or timeout.
|
||||
// The written response does not include the event header or command complete data.
|
||||
bool SendBlockingCommand(std::span<const u8> data, std::span<u8> response);
|
||||
|
||||
bool IsWiiBTModule() const;
|
||||
|
||||
private:
|
||||
@@ -91,8 +104,8 @@ private:
|
||||
bool m_showed_failed_transfer = false;
|
||||
bool m_showed_long_queue_drop = false;
|
||||
|
||||
// Some responses need to be fabricated if we aren't using the Nintendo BT module.
|
||||
bool m_is_wii_bt_module = false;
|
||||
u16 m_device_vid = 0;
|
||||
u16 m_device_pid = 0;
|
||||
|
||||
// Bluetooth spec's Num_HCI_Command_Packets.
|
||||
// This is the number of hci commands that the host is allowed to send.
|
||||
@@ -114,6 +127,7 @@ private:
|
||||
std::deque<OutstandingCommand> m_unacknowledged_commands;
|
||||
|
||||
bool IsControllerReadyForCommand() const;
|
||||
bool AreCommandsPendingResponse() const;
|
||||
|
||||
// Give the transfer to the worker and track the command appropriately.
|
||||
// This should only be used when IsControllerReadyForCommand is true.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class LibUSBBluetoothAdapter;
|
||||
|
||||
bool IsRealtekVID(u16 vid);
|
||||
bool IsKnownRealtekBluetoothDevice(u16 vid, u16 pid);
|
||||
|
||||
// Identifies the device and loads firmware as needed.
|
||||
bool InitializeRealtekBluetoothDevice(LibUSBBluetoothAdapter&);
|
||||
@@ -404,6 +404,7 @@
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\BTReal.h" />
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\BTStub.h" />
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\LibUSBBluetoothAdapter.h" />
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\RealtekFirmwareLoader.h" />
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\hci.h" />
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\l2cap.h" />
|
||||
<ClInclude Include="Core\IOS\USB\Bluetooth\WiimoteDevice.h" />
|
||||
@@ -1083,6 +1084,7 @@
|
||||
<ClCompile Include="Core\IOS\USB\Bluetooth\BTReal.cpp" />
|
||||
<ClCompile Include="Core\IOS\USB\Bluetooth\BTStub.cpp" />
|
||||
<ClCompile Include="Core\IOS\USB\Bluetooth\LibUSBBluetoothAdapter.cpp" />
|
||||
<ClCompile Include="Core\IOS\USB\Bluetooth\RealtekFirmwareLoader.cpp" />
|
||||
<ClCompile Include="Core\IOS\USB\Bluetooth\WiimoteDevice.cpp" />
|
||||
<ClCompile Include="Core\IOS\USB\Bluetooth\WiimoteHIDAttr.cpp" />
|
||||
<ClCompile Include="Core\IOS\USB\Common.cpp" />
|
||||
|
||||
Reference in New Issue
Block a user