diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp index f10b2442fc..7a70b09409 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp @@ -3,16 +3,61 @@ #include "Core/HW/WiimoteReal/IOhidapi.h" -#include +#if defined(__linux__) +#include +#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& 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& 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) diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.h b/Source/Core/Core/HW/WiimoteReal/IOhidapi.h index 9a6f6f09cf..f4340e3bc2 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; }; diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 10f1cc12ef..03341941b5 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 091532cea9..04c1e0246f 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; @@ -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