From 6c91e30a0d21b3b9be24e8f60c36c4f3fa008087 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 3 Oct 2025 04:36:16 -0500 Subject: [PATCH 1/4] WiimoteReal/IOhidapi: Remove accidentally included HID Profile byte from write test. --- Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp index f10b2442fc3..2b21af3194b 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp @@ -27,7 +27,7 @@ static bool IsDeviceUsable(const std::string& device_path) // Some third-party adapters (DolphinBar) always expose all four Wii Remotes as HIDs // even when they are not connected, which causes an endless error loop when we try to use them. // Try to write a report to the device to see if this Wii Remote is really usable. - static const u8 report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RequestStatus), 0}; + static const u8 report[] = {u8(OutputReportID::RequestStatus), 0}; const int result = hid_write(handle, report, sizeof(report)); // The DolphinBar uses EPIPE to signal the absence of a Wii Remote connected to this HID. if (result == -1 && errno != EPIPE) From 4a39ca249c2a834f6bafdce190218b57fab607e1 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 3 Oct 2025 04:44:36 -0500 Subject: [PATCH 2/4] WiimoteReal/IOhidapi: Move VID/PID check to a helper function that other backends can use in the future. --- Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp | 3 +-- Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp | 5 +++++ Source/Core/Core/HW/WiimoteReal/WiimoteReal.h | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp index 2b21af3194b..c9b11d94e4e 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp @@ -70,8 +70,7 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector& wiimotes, Wiimote { const std::string name = device->product_string ? WStringToUTF8(device->product_string) : ""; const bool is_wiimote = - IsValidDeviceName(name) || (device->vendor_id == 0x057e && - (device->product_id == 0x0306 || device->product_id == 0x0330)); + IsValidDeviceName(name) || IsKnownDeviceId({device->vendor_id, device->product_id}); if (!is_wiimote || !IsNewWiimote(device->path) || !IsDeviceUsable(device->path)) continue; diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 10f1cc12ef2..03341941b53 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -983,6 +983,11 @@ bool IsNewWiimote(const std::string& identifier) return !s_known_ids.contains(identifier); } +bool IsKnownDeviceId(const USBUtils::DeviceInfo& device_info) +{ + return device_info.vid == 0x057e && (device_info.pid == 0x0306 || device_info.pid == 0x0330); +} + void HandleWiimoteSourceChange(unsigned int index) { std::lock_guard wm_lk(g_wiimotes_mutex); diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index 103ea073f27..024ed9a7404 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -20,6 +20,7 @@ #include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h" +#include "Core/USBUtils.h" class PointerWrap; @@ -222,6 +223,8 @@ bool IsValidDeviceName(const std::string& name); bool IsBalanceBoardName(const std::string& name); bool IsNewWiimote(const std::string& identifier); +bool IsKnownDeviceId(const USBUtils::DeviceInfo&); + void HandleWiimoteSourceChange(unsigned int wiimote_number); #ifdef ANDROID From 7609220e6176efa35fa647254d92278775512728 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 3 Oct 2025 17:54:44 -0500 Subject: [PATCH 3/4] WiimoteReal/IOhidapi: Minor warning fixes and cleanups. --- Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp | 8 ++++---- Source/Core/Core/HW/WiimoteReal/IOhidapi.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp index c9b11d94e4e..95b8b6bdfa0 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp @@ -8,7 +8,6 @@ #include "Common/Assert.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" -#include "Core/HW/WiimoteCommon/WiimoteHid.h" using namespace WiimoteCommon; using namespace WiimoteReal; @@ -65,8 +64,8 @@ bool WiimoteScannerHidapi::IsReady() const void WiimoteScannerHidapi::FindWiimotes(std::vector& wiimotes, Wiimote*& board) { - hid_device_info* list = hid_enumerate(0x0, 0x0); - for (hid_device_info* device = list; device; device = device->next) + hid_device_info* list = hid_enumerate(0x0, 0x0); // FYI: 0 for all VID/PID. + for (hid_device_info* device = list; device != nullptr; device = device->next) { const std::string name = device->product_string ? WStringToUTF8(device->product_string) : ""; const bool is_wiimote = @@ -89,7 +88,7 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector& wiimotes, Wiimote hid_free_enumeration(list); } -WiimoteHidapi::WiimoteHidapi(const std::string& device_path) : m_device_path(device_path) +WiimoteHidapi::WiimoteHidapi(std::string device_path) : m_device_path(std::move(device_path)) { } @@ -145,6 +144,7 @@ int WiimoteHidapi::IORead(u8* buf) int WiimoteHidapi::IOWrite(const u8* buf, size_t len) { + assert(len > 0); DEBUG_ASSERT(buf[0] == (WR_SET_REPORT | BT_OUTPUT)); int result = hid_write(m_handle, buf + 1, len - 1); if (result == -1) diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.h b/Source/Core/Core/HW/WiimoteReal/IOhidapi.h index 9a6f6f09cf7..f4340e3bc28 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.h +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.h @@ -13,7 +13,7 @@ namespace WiimoteReal class WiimoteHidapi final : public Wiimote { public: - explicit WiimoteHidapi(const std::string& device_path); + explicit WiimoteHidapi(std::string device_path); ~WiimoteHidapi() override; std::string GetId() const override { return m_device_path; } @@ -26,7 +26,7 @@ protected: int IOWrite(const u8* buf, size_t len) override; private: - std::string m_device_path; + const std::string m_device_path; hid_device* m_handle = nullptr; }; From 4d53de5d847cefc4dc80c94daa1953c07e997a2f Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 3 Oct 2025 18:10:42 -0500 Subject: [PATCH 4/4] WiimoteReal/IOhidapi: Log the currently attached hid driver on Linux. --- Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp | 52 +++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp index 95b8b6bdfa0..7a70b09409b 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp @@ -3,7 +3,9 @@ #include "Core/HW/WiimoteReal/IOhidapi.h" -#include +#if defined(__linux__) +#include +#endif #include "Common/Assert.h" #include "Common/Logging/Log.h" @@ -12,6 +14,50 @@ using namespace WiimoteCommon; using namespace WiimoteReal; +#if defined(__linux__) +// Here we check the currently attached Linux driver just for logging purposes. +// Maybe in the future we'll be able to bind the desired HID driver somehow. +static void LogLinuxDriverName(const char* device_path) +{ + namespace fs = std::filesystem; + + const auto sys_device = "/sys/class/hidraw" / fs::path(device_path).filename() / "device"; + + // "driver" is a symlink to a path that contains the driver name. + // usually /sys/bus/hid/drivers/hid-generic (what we want) + // or this /sys/bus/hid/drivers/wiimote (what we don't want) + std::error_code err; + const auto sys_driver = fs::canonical(sys_device / "driver", err); + + if (err) + { + WARN_LOG_FMT(WIIMOTE, "Could not determine current driver of {}. error: {}", device_path, + err.message()); + return; + } + + const auto driver_name = sys_driver.filename(); + if (driver_name == "wiimote") + { + // If Linux's 'wiimote' driver is attached, we will be forever fighting with it. + // It's not going to work very well. + + // One could write fs::canonical(sys_device).filename() to (sys_driver / "unbind") + // And then also write it to "/sys/bus/hid/drivers/hid-generic/bind" + // This should create a new hidraw device with the 'hid-generic' driver. + + // But that requires elevated permissions.. Linux is annoying. + + ERROR_LOG_FMT(WIIMOTE, "Wii remote at {} has the Linux 'wiimote' driver attached.", + device_path); + } + else + { + DEBUG_LOG_FMT(WIIMOTE, "Wii remote at {} has driver: {}", device_path, driver_name.string()); + } +} +#endif + static bool IsDeviceUsable(const std::string& device_path) { hid_device* handle = hid_open_path(device_path.c_str()); @@ -73,6 +119,10 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector& wiimotes, Wiimote if (!is_wiimote || !IsNewWiimote(device->path) || !IsDeviceUsable(device->path)) continue; +#if defined(__linux__) + LogLinuxDriverName(device->path); +#endif + auto* wiimote = new WiimoteHidapi(device->path); const bool is_balance_board = IsBalanceBoardName(name) || wiimote->IsBalanceBoard(); if (is_balance_board)