Merge pull request #13989 from jordan-woyak/wmreal-hidapi-cleanup

WiimoteReal/IOhidapi: Minor changes / cleanups.
This commit is contained in:
JMC47 2025-10-09 14:06:57 -04:00 committed by GitHub
commit f43b78efb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 67 additions and 10 deletions

View file

@ -3,16 +3,61 @@
#include "Core/HW/WiimoteReal/IOhidapi.h"
#include <algorithm>
#if defined(__linux__)
#include <filesystem>
#endif
#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;
#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());
@ -27,7 +72,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)
@ -65,16 +110,19 @@ bool WiimoteScannerHidapi::IsReady() const
void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& 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 =
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;
#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)
@ -90,7 +138,7 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& 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))
{
}
@ -146,6 +194,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)

View file

@ -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;
};

View file

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

View file

@ -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;
@ -228,6 +229,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