From e9a696b160430b3fa50814bd9ad661f97807cb0e Mon Sep 17 00:00:00 2001 From: Steven Newbury Date: Sun, 19 Feb 2017 08:03:00 +0000 Subject: [PATCH] Retry opening of wiimote channels on initial failure #5997 There seems to be a race condition between a peripheral device connecting to the bluetooth controller and it being ready to use. It's very short and it depends upon the controller, some appear to connect synchronously and block until the device is ready, others report the device upon discovery but do not allow communication straight away. I don't know which is the correct behaviour, or whether it depends on the peripheral, controller or both. Anyway, Dolphin waits for a remote to appear and immediately attempts to open the communication channels, this can fail because the device isn't ready yet, delay, try again, and it works. There are other (unlikely) chances the device is busy at random moments after this initial race condition so it loops around try to reconnect. This was inspired by an earlier patch, see here: https://bugs.dolphin-emu.org/issues/5997#note-20 I can confirm that it works perfectly for me on a bluetooth controller where otherwise it's impossible to connect (Dell 380 Bluetooth 4.0). --- Source/Core/Core/HW/WiimoteReal/IOLinux.cpp | 44 +++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp b/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp index 82fa1b898b..579b442d6d 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp @@ -140,22 +140,52 @@ bool WiimoteLinux::ConnectInternal() // Output channel addr.l2_psm = htobs(WC_OUTPUT); - if ((m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + if (m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) + { + int retry = 0; + while (connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + { + // If opening channel fails sleep and try again + if (retry == 3) + { + WARN_LOG(WIIMOTE, "Unable to connect output channel to Wiimote: %s", strerror(errno)); + close(m_cmd_sock); + m_cmd_sock = -1; + return false; + } + retry++; + sleep(1); + } + } + else { WARN_LOG(WIIMOTE, "Unable to open output socket to Wiimote: %s", strerror(errno)); - close(m_cmd_sock); - m_cmd_sock = -1; return false; } // Input channel addr.l2_psm = htobs(WC_INPUT); - if ((m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + if (m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) + { + int retry = 0; + while (connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + { + // If opening channel fails sleep and try again + if (retry == 3) + { + WARN_LOG(WIIMOTE, "Unable to connect input channel to Wiimote: %s", strerror(errno)); + close(m_int_sock); + close(m_cmd_sock); + m_int_sock = m_cmd_sock = -1; + return false; + } + retry++; + sleep(1); + } + } + else { WARN_LOG(WIIMOTE, "Unable to open input socket from Wiimote: %s", strerror(errno)); - close(m_int_sock); close(m_cmd_sock); m_int_sock = m_cmd_sock = -1; return false;