summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2025-07-07 07:49:13 -0500
committerJordan Woyak <jordan.woyak@gmail.com>2025-07-23 19:58:25 -0500
commit0e90b85bab3cd263ec6510d8745ad577df118403 (patch)
tree5cbaaa5ee171def6211e03bb25e01dd00a45194a /Source
parent5336c233299ab49ce5df20eb752c76d9cb44438c (diff)
LibUSBBluetoothAdapter: Add SendBlockingCommand function.
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.cpp52
-rw-r--r--Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.h6
2 files changed, 57 insertions, 1 deletions
diff --git a/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.cpp b/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.cpp
index ab331b7bad..7c948d8ae5 100644
--- a/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.cpp
+++ b/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.cpp
@@ -14,6 +14,7 @@
#include <fmt/format.h>
#include <libusb.h>
+#include "Common/BitUtils.h"
#include "Common/MsgHandler.h"
#include "Core/Config/MainSettings.h"
@@ -62,6 +63,11 @@ bool LibUSBBluetoothAdapter::IsWiiBTModule() const
return m_is_wii_bt_module;
}
+bool LibUSBBluetoothAdapter::AreCommandsPendingResponse() const
+{
+ return !m_pending_hci_transfers.empty() || !m_unacknowledged_commands.empty();
+}
+
bool LibUSBBluetoothAdapter::HasConfiguredBluetoothDevice()
{
const int configured_vid = Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_VID);
@@ -159,7 +165,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 +400,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>();
diff --git a/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.h b/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.h
index c2bd693b10..d9f6aa33ef 100644
--- a/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.h
+++ b/Source/Core/Core/IOS/USB/Bluetooth/LibUSBBluetoothAdapter.h
@@ -53,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:
@@ -122,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.