diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp index 6305f26088..e615a69e35 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp @@ -70,17 +70,17 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector& wiimotes, Wiimote if (!is_wiimote || s_known_paths.count(device->path) != 0 || !IsDeviceUsable(device->path)) continue; - const bool is_balance_board = IsBalanceBoardName(name); - NOTICE_LOG(WIIMOTE, "Found %s at %s: %ls %ls (%04hx:%04hx)", - is_balance_board ? "balance board" : "Wiimote", device->path, - device->manufacturer_string, device->product_string, device->vendor_id, - device->product_id); - - Wiimote* wiimote = new WiimoteHidapi(device->path); + auto* wiimote = new WiimoteHidapi(device->path); + const bool is_balance_board = IsBalanceBoardName(name) || wiimote->IsBalanceBoard(); if (is_balance_board) board = wiimote; else wiimotes.push_back(wiimote); + + NOTICE_LOG(WIIMOTE, "Found %s at %s: %ls %ls (%04hx:%04hx)", + is_balance_board ? "balance board" : "Wiimote", device->path, + device->manufacturer_string, device->product_string, device->vendor_id, + device->product_id); } hid_free_enumeration(list); } @@ -98,6 +98,9 @@ WiimoteHidapi::~WiimoteHidapi() bool WiimoteHidapi::ConnectInternal() { + if (m_handle != nullptr) + return true; + m_handle = hid_open_path(m_device_path.c_str()); if (m_handle == nullptr) { diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index d2ddd283c8..a184dd2a63 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -242,6 +242,71 @@ bool Wiimote::Write() return ret != 0; } +bool Wiimote::IsBalanceBoard() +{ + if (!ConnectInternal()) + return false; + // Initialise the extension by writing 0x55 to 0xa400f0, then writing 0x00 to 0xa400fb. + static const u8 init_extension_rpt1[MAX_PAYLOAD] = { + WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55}; + static const u8 init_extension_rpt2[MAX_PAYLOAD] = { + WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00}; + static const u8 status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; + if (!IOWrite(init_extension_rpt1, sizeof(init_extension_rpt1)) || + !IOWrite(init_extension_rpt2, sizeof(init_extension_rpt2))) + { + ERROR_LOG(WIIMOTE, "IsBalanceBoard(): Failed to initialise extension."); + return false; + } + + int ret = IOWrite(status_report, sizeof(status_report)); + u8 buf[MAX_PAYLOAD]; + while (ret != 0) + { + ret = IORead(buf); + if (ret == -1) + continue; + + switch (buf[1]) + { + case WM_STATUS_REPORT: + { + const auto* status = reinterpret_cast(&buf[2]); + // A Balance Board has a Balance Board extension. + if (!status->extension) + return false; + // Read two bytes from 0xa400fe to identify the extension. + static const u8 identify_ext_rpt[] = { + WM_SET_REPORT | WM_BT_OUTPUT, WM_READ_DATA, 0x04, 0xa4, 0x00, 0xfe, 0x02, 0x00}; + ret = IOWrite(identify_ext_rpt, sizeof(identify_ext_rpt)); + break; + } + case WM_READ_DATA_REPLY: + { + const auto* reply = reinterpret_cast(&buf[2]); + if (Common::swap16(reply->address) != 0x00fe) + { + ERROR_LOG(WIIMOTE, "IsBalanceBoard(): Received unexpected data reply for address %X", + Common::swap16(reply->address)); + return false; + } + // A Balance Board ext can be identified by checking for 0x0402. + return reply->data[0] == 0x04 && reply->data[1] == 0x02; + } + case WM_ACK_DATA: + { + const auto* ack = reinterpret_cast(&buf[2]); + if (ack->reportID == WM_READ_DATA && ack->errorID != 0x00) + { + WARN_LOG(WIIMOTE, "Failed to read from 0xa400fe, assuming Wiimote is not a Balance Board."); + return false; + } + } + } + } + return false; +} + static bool IsDataReport(const Report& rpt) { return rpt.size() >= 2 && rpt[1] >= WM_REPORT_CORE; diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index bd322543af..f5b1cd1446 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -41,6 +41,8 @@ public: void Read(); bool Write(); + bool IsBalanceBoard(); + void StartThread(); void StopThread();