diff --git a/CMakeLists.txt b/CMakeLists.txt
index 528b1cbb17..4d292421a1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,7 @@
# General setup
#
cmake_minimum_required(VERSION 2.8.8)
+project(dolphin-emu)
option(USE_EGL "Enables EGL OpenGL Interface" OFF)
option(TRY_X11 "Enables X11 Support" ON)
@@ -13,6 +14,9 @@ option(ENABLE_LTO "Enables Link Time Optimization" OFF)
option(ENABLE_GENERIC "Enables generic build that should run on any little-endian host" OFF)
if(APPLE)
option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF)
+ option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" OFF)
+elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ option(INSTALL_UDEV_RULES "Install udev rules for hidraw/usb devices" OFF)
endif()
option(ENCODE_FRAMEDUMPS "Encode framedumps in AVI format" ON)
@@ -21,9 +25,6 @@ option(FASTLOG "Enable all logs" OFF)
option(OPROFILING "Enable profiling" OFF)
option(GDBSTUB "Enable gdb stub for remote debugging." OFF)
-if(APPLE)
- option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" OFF)
-endif()
########################################
# Optional Targets
# TODO: Add DSPSpy
@@ -45,7 +46,6 @@ if (APPLE)
endif()
endif()
endif()
-project(dolphin-emu)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/CMakeTests)
set(DOLPHIN_IS_STABLE FALSE)
# Libraries to link
@@ -292,7 +292,6 @@ if(APPLE)
find_library(COREFUND_LIBRARY CoreFoundation)
find_library(CORESERV_LIBRARY CoreServices)
find_library(FOUNDATION_LIBRARY foundation)
- find_library(IOB_LIBRARY IOBluetooth)
find_library(IOK_LIBRARY IOKit)
find_library(QUICKTIME_LIBRARY QuickTime)
find_library(WEBKIT_LIBRARY WebKit)
@@ -379,15 +378,6 @@ if(NOT ANDROID)
message("ao NOT found, disabling ao sound backend")
endif(AO_FOUND)
- check_lib(BLUEZ bluez QUIET)
- if(BLUEZ_FOUND)
- add_definitions(-DHAVE_BLUEZ=1)
- message("bluez found, enabling bluetooth support")
- else()
- add_definitions(-DHAVE_BLUEZ=0)
- message("bluez NOT found, disabling bluetooth support")
- endif(BLUEZ_FOUND)
-
check_lib(PULSEAUDIO libpulse QUIET)
if(PULSEAUDIO_FOUND)
add_definitions(-DHAVE_PULSEAUDIO=1)
@@ -595,10 +585,19 @@ endif()
include(FindLibUSB OPTIONAL)
if(LIBUSB_FOUND)
- message("Using shared LibUSB")
+ message("Using shared libusb")
add_definitions(-D__LIBUSB__)
include_directories(${LIBUSB_INCLUDE_DIR})
-endif(LIBUSB_FOUND)
+ list(APPEND LIBS ${LIBUSB_LIBRARIES})
+elseif(ANDROID)
+ message("Using static libusb from Externals")
+ add_subdirectory(Externals/libusb/libusb)
+ include_directories(Externals/libusb/libusb)
+ list(APPEND LIBS usb-1.0)
+else()
+ message(FATAL_ERROR "libusb is required. Either extend the CMakeLists.txt file to support your OS"
+ " or just install libusb as a shared library.")
+endif()
set(SFML_REQD_VERSION 2.1)
if(NOT APPLE AND NOT ANDROID)
@@ -665,6 +664,32 @@ else()
mark_as_advanced(ICONV_INCLUDE_DIR ICONV_LIBRARIES)
endif()
+include(FindHIDAPI OPTIONAL)
+find_package(HIDAPI)
+if(HIDAPI_FOUND)
+ message("Using shared ${HIDAPI_LIBRARIES} ${HIDAPI_VERSION}")
+ include_directories(${HIDAPI_INCLUDE_DIRS})
+ list(APPEND LIBS ${HIDAPI_LIBRARIES})
+else()
+ include_directories(Externals/hidapi/hidapi)
+ if(APPLE)
+ message("Using static hidapi from Externals")
+ add_subdirectory(Externals/hidapi/mac)
+ list(APPEND LIBS hidapi)
+ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ANDROID)
+ message("Using static hidapi-hidraw from Externals")
+ add_subdirectory(Externals/hidapi/linux)
+ list(APPEND LIBS hidapi-hidraw udev)
+ else()
+ message("Using static hidapi-libusb from Externals")
+ add_subdirectory(Externals/hidapi/libusb)
+ list(APPEND LIBS hidapi-libusb)
+ endif()
+endif()
+if(INSTALL_UDEV_RULES)
+ install(FILES Installer/90-wiimote.rules /etc/udev/rules.d/)
+endif()
+
if(ENABLE_QT)
find_package(Qt5Widgets REQUIRED)
message("Found Qt version ${Qt5Core_VERSION}, enabling the Qt backend")
diff --git a/CMakeTests/FindHIDAPI.cmake b/CMakeTests/FindHIDAPI.cmake
new file mode 100644
index 0000000000..b75110ab12
--- /dev/null
+++ b/CMakeTests/FindHIDAPI.cmake
@@ -0,0 +1,9 @@
+find_path(HIDAPI_INCLUDE_DIR NAMES hidapi.h PATH_SUFFIXES hidapi)
+find_library(HIDAPI_LIBRARY NAMES hidapi hidapi-hidraw hidapi-libusb)
+set(HIDAPI_LIBRARIES ${HIDAPI_LIBRARY})
+set(HIDAPI_INCLUDE_DIRS ${HIDAPI_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(HIDAPI DEFAULT_MSG HIDAPI_LIBRARY HIDAPI_INCLUDE_DIR)
+
+mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY)
diff --git a/Externals/hidapi/libusb/CMakeLists.txt b/Externals/hidapi/libusb/CMakeLists.txt
new file mode 100644
index 0000000000..5bb2c08688
--- /dev/null
+++ b/Externals/hidapi/libusb/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(hidapi-libusb hid.c)
diff --git a/Externals/hidapi/linux/CMakeLists.txt b/Externals/hidapi/linux/CMakeLists.txt
new file mode 100644
index 0000000000..f7984bd755
--- /dev/null
+++ b/Externals/hidapi/linux/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(hidapi-hidraw hid.c)
diff --git a/Externals/hidapi/mac/CMakeLists.txt b/Externals/hidapi/mac/CMakeLists.txt
new file mode 100644
index 0000000000..ccd2898ed4
--- /dev/null
+++ b/Externals/hidapi/mac/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(hidapi hid.c)
diff --git a/Externals/libusb/libusb/CMakeLists.txt b/Externals/libusb/libusb/CMakeLists.txt
new file mode 100644
index 0000000000..30f297823e
--- /dev/null
+++ b/Externals/libusb/libusb/CMakeLists.txt
@@ -0,0 +1,17 @@
+# This file is only used for Android (because I'm lazy).
+# We don't use CMake on Windows and just require libusb to be installed everywhere else.
+
+set(SRCS
+ core.c
+ descriptor.c
+ hotplug.c
+ io.c
+ strerror.c
+ sync.c
+)
+
+include_directories(BEFORE ../android)
+
+add_subdirectory(os)
+add_library(usb-1.0 STATIC ${SRCS})
+target_link_libraries(usb-1.0 usb-os)
diff --git a/Externals/libusb/libusb/os/CMakeLists.txt b/Externals/libusb/libusb/os/CMakeLists.txt
new file mode 100644
index 0000000000..e0add49808
--- /dev/null
+++ b/Externals/libusb/libusb/os/CMakeLists.txt
@@ -0,0 +1,7 @@
+include_directories(..)
+add_library(usb-os STATIC
+ linux_netlink.c
+ linux_usbfs.c
+ poll_posix.c
+ threads_posix.c
+)
diff --git a/Externals/libusb/msvc/libusb_static_2013.vcxproj b/Externals/libusb/msvc/libusb_static_2013.vcxproj
index 45a88c567c..3ba53075cc 100644
--- a/Externals/libusb/msvc/libusb_static_2013.vcxproj
+++ b/Externals/libusb/msvc/libusb_static_2013.vcxproj
@@ -27,7 +27,6 @@
StaticLibrary
Unicode
- true
v120
@@ -38,7 +37,6 @@
StaticLibrary
Unicode
- true
v120
diff --git a/Installer/90-wiimote.rules b/Installer/90-wiimote.rules
new file mode 100644
index 0000000000..71c9c30fde
--- /dev/null
+++ b/Installer/90-wiimote.rules
@@ -0,0 +1,8 @@
+# This is how you can match Wiimotes (and Wiimote-emulating devices like the DolphinBar) in udev.
+# If you are a package maintainer you'll probably want to restrict permissions to a group: GROUP="plugdev", MODE="0660".
+
+# Wiimote or DolphinBar
+SUBSYSTEMS=="hid", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="0306", MODE="0666"
+
+# newer Wiimotes (RVL-CNT-01-TR)
+SUBSYSTEMS=="hid", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="0330", MODE="0666"
diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index 3af53428ac..cdd3a694e7 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -116,6 +116,7 @@ set(SRCS ActionReplay.cpp
HW/SI_DeviceGBA.cpp
HW/SI_DeviceGCController.cpp
HW/SI_DeviceGCSteeringWheel.cpp
+ HW/SI_GCAdapter.cpp
HW/Sram.cpp
HW/StreamADPCM.cpp
HW/SystemTimers.cpp
@@ -132,6 +133,7 @@ set(SRCS ActionReplay.cpp
HW/WiimoteEmu/EmuSubroutines.cpp
HW/WiimoteEmu/Encryption.cpp
HW/WiimoteEmu/Speaker.cpp
+ HW/WiimoteReal/IOhidapi.cpp
HW/WiimoteReal/WiimoteReal.cpp
HW/WiiSaveCrypted.cpp
IPC_HLE/ICMPLin.cpp
@@ -140,6 +142,7 @@ set(SRCS ActionReplay.cpp
IPC_HLE/WII_IPC_HLE_Device_es.cpp
IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp
IPC_HLE/WII_IPC_HLE_Device_fs.cpp
+ IPC_HLE/WII_IPC_HLE_Device_hid.cpp
IPC_HLE/WII_Socket.cpp
IPC_HLE/WII_IPC_HLE_Device_net.cpp
IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp
@@ -245,29 +248,15 @@ set(LIBS
z
)
-if(LIBUSB_FOUND)
- # Using shared LibUSB
- set(LIBS ${LIBS} ${LIBUSB_LIBRARIES})
- set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp
- HW/SI_GCAdapter.cpp)
-endif(LIBUSB_FOUND)
set(LIBS ${LIBS} ${POLARSSL_LIBRARY})
if(WIN32)
- set(SRCS ${SRCS} HW/BBA-TAP/TAP_Win32.cpp HW/WiimoteReal/IOWin.cpp)
+ set(SRCS ${SRCS} HW/BBA-TAP/TAP_Win32.cpp)
elseif(APPLE)
- set(SRCS ${SRCS} HW/BBA-TAP/TAP_Apple.cpp HW/WiimoteReal/IOdarwin.mm)
- set(LIBS ${LIBS}
- ${IOB_LIBRARY})
+ set(SRCS ${SRCS} HW/BBA-TAP/TAP_Apple.cpp)
elseif(UNIX)
set(SRCS ${SRCS} HW/BBA-TAP/TAP_Unix.cpp)
- if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND BLUEZ_FOUND)
- set(SRCS ${SRCS} HW/WiimoteReal/IONix.cpp)
- set(LIBS ${LIBS} bluetooth)
- else()
- set(SRCS ${SRCS} HW/WiimoteReal/IODummy.cpp)
- endif()
endif()
if(PORTAUDIO_FOUND)
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index ca37ca6621..1b356266b5 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -169,7 +169,7 @@
-
+
@@ -470,6 +470,9 @@
{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}
+
+ {549d32d8-1640-46f9-9d78-bae6eb0d723d}
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index 4ddaee9aa4..fda79ce620 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -484,7 +484,7 @@
HW %28Flipper/Hollywood%29\Wiimote\Emu
-
+
HW %28Flipper/Hollywood%29\Wiimote\Real
diff --git a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp b/Source/Core/Core/HW/WiimoteReal/IODummy.cpp
deleted file mode 100644
index 090c7141e5..0000000000
--- a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include "Common/CommonTypes.h"
-#include "Core/HW/WiimoteReal/WiimoteReal.h"
-
-namespace WiimoteReal
-{
-
-WiimoteScanner::WiimoteScanner()
-{}
-
-WiimoteScanner::~WiimoteScanner()
-{}
-
-void WiimoteScanner::Update()
-{}
-
-void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board)
-{
- found_wiimotes.clear();
- found_board = nullptr;
-}
-
-bool WiimoteScanner::IsReady() const
-{
- return false;
-}
-
-};
diff --git a/Source/Core/Core/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/HW/WiimoteReal/IONix.cpp
deleted file mode 100644
index d287121385..0000000000
--- a/Source/Core/Core/HW/WiimoteReal/IONix.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2014 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include
-#include
-#include
-#include
-
-#include "Common/Common.h"
-#include "Core/HW/WiimoteReal/WiimoteReal.h"
-
-namespace WiimoteReal
-{
-
-class WiimoteLinux final : public Wiimote
-{
-public:
- WiimoteLinux(bdaddr_t bdaddr);
- ~WiimoteLinux() override;
-
-protected:
- bool ConnectInternal() override;
- void DisconnectInternal() override;
- bool IsConnected() const override;
- void IOWakeup() override;
- int IORead(u8* buf) override;
- int IOWrite(u8 const* buf, size_t len) override;
-
-private:
- bdaddr_t m_bdaddr; // Bluetooth address
- int m_cmd_sock; // Command socket
- int m_int_sock; // Interrupt socket
- int m_wakeup_pipe_w;
- int m_wakeup_pipe_r;
-};
-
-WiimoteScanner::WiimoteScanner()
- : m_want_wiimotes()
- , device_id(-1)
- , device_sock(-1)
-{
- // Get the id of the first bluetooth device.
- device_id = hci_get_route(nullptr);
- if (device_id < 0)
- {
- NOTICE_LOG(WIIMOTE, "Bluetooth not found.");
- return;
- }
-
- // Create a socket to the device
- device_sock = hci_open_dev(device_id);
- if (device_sock < 0)
- {
- ERROR_LOG(WIIMOTE, "Unable to open bluetooth.");
- return;
- }
-}
-
-bool WiimoteScanner::IsReady() const
-{
- return device_sock > 0;
-}
-
-WiimoteScanner::~WiimoteScanner()
-{
- if (IsReady())
- close(device_sock);
-}
-
-void WiimoteScanner::Update()
-{}
-
-void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board)
-{
- // supposedly 1.28 seconds
- int const wait_len = 1;
-
- int const max_infos = 255;
- inquiry_info scan_infos[max_infos] = {};
- auto* scan_infos_ptr = scan_infos;
- found_board = nullptr;
-
- // Scan for bluetooth devices
- int const found_devices = hci_inquiry(device_id, wait_len, max_infos, nullptr, &scan_infos_ptr, IREQ_CACHE_FLUSH);
- if (found_devices < 0)
- {
- ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices.");
- return;
- }
-
- DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices);
-
- // Display discovered devices
- for (int i = 0; i < found_devices; ++i)
- {
- ERROR_LOG(WIIMOTE, "found a device...");
-
- // BT names are a maximum of 248 bytes apparently
- char name[255] = {};
- if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 1000) < 0)
- {
- ERROR_LOG(WIIMOTE, "name request failed");
- continue;
- }
-
- ERROR_LOG(WIIMOTE, "device name %s", name);
- if (IsValidBluetoothName(name))
- {
- bool new_wiimote = true;
-
- // TODO: do this
-
- // Determine if this wiimote has already been found.
- //for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j)
- //{
- // if (wm[j] && bacmp(&scan_infos[i].bdaddr,&wm[j]->bdaddr) == 0)
- // new_wiimote = false;
- //}
-
- if (new_wiimote)
- {
- // Found a new device
- char bdaddr_str[18] = {};
- ba2str(&scan_infos[i].bdaddr, bdaddr_str);
-
- Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr);
- if (IsBalanceBoardName(name))
- {
- found_board = wm;
- NOTICE_LOG(WIIMOTE, "Found balance board (%s).", bdaddr_str);
- }
- else
- {
- found_wiimotes.push_back(wm);
- NOTICE_LOG(WIIMOTE, "Found wiimote (%s).", bdaddr_str);
- }
- }
- }
- }
-
-}
-
-WiimoteLinux::WiimoteLinux(bdaddr_t bdaddr) : Wiimote(), m_bdaddr(bdaddr)
-{
- m_cmd_sock = -1;
- m_int_sock = -1;
-
- int fds[2];
- if (pipe(fds))
- {
- ERROR_LOG(WIIMOTE, "pipe failed");
- abort();
- }
- m_wakeup_pipe_w = fds[1];
- m_wakeup_pipe_r = fds[0];
-}
-
-WiimoteLinux::~WiimoteLinux()
-{
- Shutdown();
- close(m_wakeup_pipe_w);
- close(m_wakeup_pipe_r);
-}
-
-// Connect to a wiimote with a known address.
-bool WiimoteLinux::ConnectInternal()
-{
- sockaddr_l2 addr = {};
- addr.l2_family = AF_BLUETOOTH;
- addr.l2_bdaddr = m_bdaddr;
- addr.l2_cid = 0;
-
- // Output channel
- addr.l2_psm = htobs(WM_OUTPUT_CHANNEL);
- if ((m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
- connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0)
- {
- 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(WM_INPUT_CHANNEL);
- if ((m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
- connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0)
- {
- 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;
- }
-
- return true;
-}
-
-void WiimoteLinux::DisconnectInternal()
-{
- close(m_cmd_sock);
- close(m_int_sock);
-
- m_cmd_sock = -1;
- m_int_sock = -1;
-}
-
-bool WiimoteLinux::IsConnected() const
-{
- return m_cmd_sock != -1;// && int_sock != -1;
-}
-
-void WiimoteLinux::IOWakeup()
-{
- char c = 0;
- if (write(m_wakeup_pipe_w, &c, 1) != 1)
- {
- ERROR_LOG(WIIMOTE, "Unable to write to wakeup pipe.");
- }
-}
-
-// positive = read packet
-// negative = didn't read packet
-// zero = error
-int WiimoteLinux::IORead(u8* buf)
-{
- // Block select for 1/2000th of a second
-
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(m_int_sock, &fds);
- FD_SET(m_wakeup_pipe_r, &fds);
-
- if (select(m_int_sock + 1, &fds, nullptr, nullptr, nullptr) == -1)
- {
- ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", m_index + 1);
- return -1;
- }
-
- if (FD_ISSET(m_wakeup_pipe_r, &fds))
- {
- char c;
- if (read(m_wakeup_pipe_r, &c, 1) != 1)
- {
- ERROR_LOG(WIIMOTE, "Unable to read from wakeup pipe.");
- }
- return -1;
- }
-
- if (!FD_ISSET(m_int_sock, &fds))
- return -1;
-
- // Read the pending message into the buffer
- int r = read(m_int_sock, buf, MAX_PAYLOAD);
- if (r == -1)
- {
- // Error reading data
- ERROR_LOG(WIIMOTE, "Receiving data from wiimote %i.", m_index + 1);
-
- if (errno == ENOTCONN)
- {
- // This can happen if the bluetooth dongle is disconnected
- ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. "
- "Wiimote %i will be disconnected.", m_index + 1);
- }
-
- r = 0;
- }
-
- return r;
-}
-
-int WiimoteLinux::IOWrite(u8 const* buf, size_t len)
-{
- return write(m_int_sock, buf, (int)len);
-}
-
-}; // WiimoteReal
diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
deleted file mode 100644
index 1605cfd20d..0000000000
--- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
+++ /dev/null
@@ -1,954 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-// The following Windows headers must be included AFTER windows.h.
-#include //NOLINT
-#include //NOLINT
-#include //NOLINT
-
-#include "Common/Common.h"
-#include "Common/StringUtil.h"
-
-#include "Core/HW/WiimoteReal/WiimoteReal.h"
-
-//#define AUTHENTICATE_WIIMOTES
-#define SHARE_WRITE_WIIMOTES
-
-// Create func_t function pointer type and declare a nullptr-initialized static variable of that
-// type named "pfunc".
-#define DYN_FUNC_DECLARE(func) \
- typedef decltype(&func) func ## _t; \
- static func ## _t p ## func = nullptr;
-
-DYN_FUNC_DECLARE(HidD_GetHidGuid);
-DYN_FUNC_DECLARE(HidD_GetAttributes);
-DYN_FUNC_DECLARE(HidD_SetOutputReport);
-DYN_FUNC_DECLARE(HidD_GetProductString);
-
-DYN_FUNC_DECLARE(BluetoothFindDeviceClose);
-DYN_FUNC_DECLARE(BluetoothFindFirstDevice);
-DYN_FUNC_DECLARE(BluetoothFindFirstRadio);
-DYN_FUNC_DECLARE(BluetoothFindNextDevice);
-DYN_FUNC_DECLARE(BluetoothFindNextRadio);
-DYN_FUNC_DECLARE(BluetoothFindRadioClose);
-DYN_FUNC_DECLARE(BluetoothGetRadioInfo);
-DYN_FUNC_DECLARE(BluetoothRemoveDevice);
-DYN_FUNC_DECLARE(BluetoothSetServiceState);
-DYN_FUNC_DECLARE(BluetoothAuthenticateDeviceEx);
-DYN_FUNC_DECLARE(BluetoothEnumerateInstalledServices);
-
-#undef DYN_FUNC_DECLARE
-
-static HINSTANCE s_hid_lib = nullptr;
-static HINSTANCE s_bthprops_lib = nullptr;
-
-static bool s_loaded_ok = false;
-
-std::unordered_map g_connect_times;
-
-#ifdef SHARE_WRITE_WIIMOTES
-std::unordered_set> g_connected_wiimotes;
-std::mutex g_connected_wiimotes_lock;
-#endif
-
-#define DYN_FUNC_UNLOAD(func) \
- p ## func = nullptr;
-
-// Attempt to load the function from the given module handle.
-#define DYN_FUNC_LOAD(module, func) \
- p ## func = ( func ## _t)::GetProcAddress(module, # func ); \
- if (! p ## func ) \
- { \
- return false; \
- }
-
-bool load_hid()
-{
- auto loader = [&]()
- {
- s_hid_lib = ::LoadLibrary(_T("hid.dll"));
- if (!s_hid_lib)
- {
- return false;
- }
-
- DYN_FUNC_LOAD(s_hid_lib, HidD_GetHidGuid);
- DYN_FUNC_LOAD(s_hid_lib, HidD_GetAttributes);
- DYN_FUNC_LOAD(s_hid_lib, HidD_SetOutputReport);
- DYN_FUNC_LOAD(s_hid_lib, HidD_GetProductString);
-
- return true;
- };
-
- bool loaded_ok = loader();
-
- if (!loaded_ok)
- {
- DYN_FUNC_UNLOAD(HidD_GetHidGuid);
- DYN_FUNC_UNLOAD(HidD_GetAttributes);
- DYN_FUNC_UNLOAD(HidD_SetOutputReport);
- DYN_FUNC_UNLOAD(HidD_GetProductString);
-
- if (s_hid_lib)
- {
- ::FreeLibrary(s_hid_lib);
- s_hid_lib = nullptr;
- }
- }
-
- return loaded_ok;
-}
-
-bool load_bthprops()
-{
- auto loader = [&]()
- {
- s_bthprops_lib = ::LoadLibrary(_T("bthprops.cpl"));
- if (!s_bthprops_lib)
- {
- return false;
- }
-
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindDeviceClose);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindFirstDevice);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindFirstRadio);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindNextDevice);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindNextRadio);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindRadioClose);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothGetRadioInfo);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothRemoveDevice);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothSetServiceState);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothAuthenticateDeviceEx);
- DYN_FUNC_LOAD(s_bthprops_lib, BluetoothEnumerateInstalledServices);
-
- return true;
- };
-
- bool loaded_ok = loader();
-
- if (!loaded_ok)
- {
- DYN_FUNC_UNLOAD(BluetoothFindDeviceClose);
- DYN_FUNC_UNLOAD(BluetoothFindFirstDevice);
- DYN_FUNC_UNLOAD(BluetoothFindFirstRadio);
- DYN_FUNC_UNLOAD(BluetoothFindNextDevice);
- DYN_FUNC_UNLOAD(BluetoothFindNextRadio);
- DYN_FUNC_UNLOAD(BluetoothFindRadioClose);
- DYN_FUNC_UNLOAD(BluetoothGetRadioInfo);
- DYN_FUNC_UNLOAD(BluetoothRemoveDevice);
- DYN_FUNC_UNLOAD(BluetoothSetServiceState);
- DYN_FUNC_UNLOAD(BluetoothAuthenticateDeviceEx);
- DYN_FUNC_UNLOAD(BluetoothEnumerateInstalledServices);
-
- if (s_bthprops_lib)
- {
- ::FreeLibrary(s_bthprops_lib);
- s_bthprops_lib = nullptr;
- }
- }
-
- return loaded_ok;
-}
-
-#undef DYN_FUNC_LOAD
-#undef DYN_FUNC_UNLOAD
-
-inline void init_lib()
-{
- static bool initialized = false;
-
- if (!initialized)
- {
- // Only try once
- initialized = true;
-
- // After these calls, we know all dynamically loaded APIs will either all be valid or
- // all nullptr.
- if (!load_hid() || !load_bthprops())
- {
- NOTICE_LOG(WIIMOTE,
- "Failed to load bluetooth support libraries, wiimotes will not function");
- return;
- }
-
- s_loaded_ok = true;
- }
-}
-
-namespace WiimoteReal
-{
-
-class WiimoteWindows final : public Wiimote
-{
-public:
- WiimoteWindows(const std::basic_string& path);
- ~WiimoteWindows() override;
-
-protected:
- bool ConnectInternal() override;
- void DisconnectInternal() override;
- bool IsConnected() const override;
- void IOWakeup() override;
- int IORead(u8* buf) override;
- int IOWrite(u8 const* buf, size_t len) override;
-
-private:
- std::basic_string m_devicepath; // Unique wiimote reference
- HANDLE m_dev_handle; // HID handle
- OVERLAPPED m_hid_overlap_read; // Overlap handles
- OVERLAPPED m_hid_overlap_write;
- enum win_bt_stack_t m_stack; // Type of bluetooth stack to use
-};
-
-int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len, DWORD* written);
-int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index);
-
-template
-void ProcessWiimotes(bool new_scan, T& callback);
-
-bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT&);
-void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&);
-bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&);
-
-WiimoteScanner::WiimoteScanner()
- : m_run_thread()
- , m_want_wiimotes()
-{
- init_lib();
-}
-
-WiimoteScanner::~WiimoteScanner()
-{
- // TODO: what do we want here?
-#if 0
- ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
- {
- RemoveWiimote(btdi);
- });
-#endif
-}
-
-void WiimoteScanner::Update()
-{
- if (!s_loaded_ok)
- return;
-
- bool forgot_some = false;
-
- ProcessWiimotes(false, [&](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
- {
- forgot_some |= ForgetWiimote(btdi);
- });
-
- // Some hacks that allows disconnects to be detected before connections are handled
- // workaround for wiimote 1 moving to slot 2 on temporary disconnect
- if (forgot_some)
- SLEEP(100);
-}
-
-// Find and connect wiimotes.
-// Does not replace already found wiimotes even if they are disconnected.
-// wm is an array of max_wiimotes wiimotes
-// Returns the total number of found and connected wiimotes.
-void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board)
-{
- if (!s_loaded_ok)
- return;
-
- ProcessWiimotes(true, [](HANDLE hRadio, const BLUETOOTH_RADIO_INFO& rinfo, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
- {
- ForgetWiimote(btdi);
- AttachWiimote(hRadio, rinfo, btdi);
- });
-
- // Get the device id
- GUID device_id;
- pHidD_GetHidGuid(&device_id);
-
- // Get all hid devices connected
- HDEVINFO const device_info = SetupDiGetClassDevs(&device_id, nullptr, nullptr, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
-
- SP_DEVICE_INTERFACE_DATA device_data;
- device_data.cbSize = sizeof(device_data);
- PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = nullptr;
-
- for (int index = 0; SetupDiEnumDeviceInterfaces(device_info, nullptr, &device_id, index, &device_data); ++index)
- {
- // Get the size of the data block required
- DWORD len;
- SetupDiGetDeviceInterfaceDetail(device_info, &device_data, nullptr, 0, &len, nullptr);
- detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(len);
- detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
-
- // Query the data for this device
- if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, nullptr, nullptr))
- {
- std::basic_string device_path(detail_data->DevicePath);
- Wiimote* wm = new WiimoteWindows(device_path);
- bool real_wiimote = false, is_bb = false;
-
- CheckDeviceType(device_path, real_wiimote, is_bb);
- if (is_bb)
- {
- found_board = wm;
- }
- else if (real_wiimote)
- {
- found_wiimotes.push_back(wm);
- }
- else
- {
- delete wm;
- }
- }
-
- free(detail_data);
- }
-
- SetupDiDestroyDeviceInfoList(device_info);
-
- // Don't mind me, just a random sleep to fix stuff on Windows
- //if (!wiimotes.empty())
- // SLEEP(2000);
-
-}
-int CheckDeviceType_Write(HANDLE &dev_handle, const u8* buf, size_t size, int attempts)
-{
- OVERLAPPED hid_overlap_write = OVERLAPPED();
- hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr);
- enum win_bt_stack_t stack = MSBT_STACK_UNKNOWN;
-
- DWORD written = 0;
-
- for (; attempts>0; --attempts)
- {
- if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, size, &written))
- break;
- }
-
- CloseHandle(hid_overlap_write.hEvent);
-
- return written;
-}
-
-int CheckDeviceType_Read(HANDLE &dev_handle, u8* buf, int attempts)
-{
- OVERLAPPED hid_overlap_read = OVERLAPPED();
- hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr);
- int read = 0;
- for (; attempts>0; --attempts)
- {
- read = _IORead(dev_handle, hid_overlap_read, buf, 1);
- if (read > 0)
- break;
- }
-
- CloseHandle(hid_overlap_read.hEvent);
-
- return read;
-}
-
-// A convoluted way of checking if a device is a Wii Balance Board and if it is a connectible Wiimote.
-// Because nothing on Windows should be easy.
-// (We can't seem to easily identify the bluetooth device an HID device belongs to...)
-void WiimoteScanner::CheckDeviceType(std::basic_string &devicepath, bool &real_wiimote, bool &is_bb)
-{
- real_wiimote = false;
- is_bb = false;
-
-#ifdef SHARE_WRITE_WIIMOTES
- std::lock_guard lk(g_connected_wiimotes_lock);
- if (g_connected_wiimotes.count(devicepath) != 0)
- return;
-#endif
-
- HANDLE dev_handle = CreateFile(devicepath.c_str(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
- nullptr);
- if (dev_handle == INVALID_HANDLE_VALUE)
- return;
- // enable to only check for official nintendo wiimotes/bb's
- bool check_vidpid = false;
- HIDD_ATTRIBUTES attrib;
- attrib.Size = sizeof(attrib);
- if (!check_vidpid ||
- (pHidD_GetAttributes(dev_handle, &attrib) &&
- (attrib.VendorID == 0x057e) &&
- (attrib.ProductID == 0x0306)))
- {
- // max_cycles insures we are never stuck here due to bad coding...
- int max_cycles = 20;
- u8 buf[MAX_PAYLOAD] = {0};
-
- u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
- // The new way to initialize the extension is by writing 0x55 to 0x(4)A400F0, then writing 0x00 to 0x(4)A400FB
- // 52 16 04 A4 00 F0 01 55
- // 52 16 04 A4 00 FB 01 00
- u8 const disable_enc_pt1_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55};
- u8 const disable_enc_pt2_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00};
-
- CheckDeviceType_Write(dev_handle,
- disable_enc_pt1_report,
- sizeof(disable_enc_pt1_report),
- 1);
- CheckDeviceType_Write(dev_handle,
- disable_enc_pt2_report,
- sizeof(disable_enc_pt2_report),
- 1);
-
- int rc = CheckDeviceType_Write(dev_handle,
- req_status_report,
- sizeof(req_status_report),
- 1);
-
- while (rc > 0 && --max_cycles > 0)
- {
- if ((rc = CheckDeviceType_Read(dev_handle, buf, 1)) <= 0)
- {
- // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Read failed...");
- break;
- }
-
- switch (buf[1])
- {
- case WM_STATUS_REPORT:
- {
- real_wiimote = true;
-
- // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Status Report");
- wm_status_report * wsr = (wm_status_report*)&buf[2];
- if (wsr->extension)
- {
- // Wiimote with extension, we ask it what kind.
- u8 read_ext[MAX_PAYLOAD] = {0};
- read_ext[0] = WM_SET_REPORT | WM_BT_OUTPUT;
- read_ext[1] = WM_READ_DATA;
- // Extension type register.
- *(u32*)&read_ext[2] = Common::swap32(0x4a400fa);
- // Size.
- *(u16*)&read_ext[6] = Common::swap16(6);
- rc = CheckDeviceType_Write(dev_handle, read_ext, 8, 1);
- }
- else
- {
- // Normal Wiimote, exit while and be happy.
- rc = -1;
- }
- break;
- }
- case WM_ACK_DATA:
- {
- real_wiimote = true;
- //wm_acknowledge * wm = (wm_acknowledge*)&buf[2];
- //DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Ack Error: %X ReportID: %X", wm->errorID, wm->reportID);
- break;
- }
- case WM_READ_DATA_REPLY:
- {
- // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Data Reply");
- wm_read_data_reply * wrdr
- = (wm_read_data_reply*)&buf[2];
- // Check if it has returned what we asked.
- if (Common::swap16(wrdr->address) == 0x00fa)
- {
- real_wiimote = true;
- // 0x020420A40000ULL means balance board.
- u64 ext_type = (*(u64*)&wrdr->data[0]);
- // DEBUG_LOG(WIIMOTE,
- // "CheckDeviceType: GOT EXT TYPE %llX",
- // ext_type);
- is_bb = (ext_type == 0x020420A40000ULL);
- }
- else
- {
- ERROR_LOG(WIIMOTE,
- "CheckDeviceType: GOT UNREQUESTED ADDRESS %X",
- Common::swap16(wrdr->address));
- }
- // force end
- rc = -1;
-
- break;
- }
- default:
- {
- // We let read try again incase there is another packet waiting.
- // DEBUG_LOG(WIIMOTE, "CheckDeviceType: GOT UNKNOWN REPLY: %X", buf[1]);
- break;
- }
- }
- }
- }
- CloseHandle(dev_handle);
-}
-
-bool WiimoteScanner::IsReady() const
-{
- if (!s_loaded_ok)
- {
- return false;
- }
-
- // TODO: don't search for a radio each time
-
- BLUETOOTH_FIND_RADIO_PARAMS radioParam;
- radioParam.dwSize = sizeof(radioParam);
-
- HANDLE hRadio;
- HBLUETOOTH_RADIO_FIND hFindRadio = pBluetoothFindFirstRadio(&radioParam, &hRadio);
-
- if (nullptr != hFindRadio)
- {
- pBluetoothFindRadioClose(hFindRadio);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-// Connect to a wiimote with a known device path.
-bool WiimoteWindows::ConnectInternal()
-{
- if (IsConnected())
- return false;
-
-#ifdef SHARE_WRITE_WIIMOTES
- std::lock_guard lk(g_connected_wiimotes_lock);
- if (g_connected_wiimotes.count(m_devicepath) != 0)
- return false;
-
- auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE;
-#else
- // Having no FILE_SHARE_WRITE disallows us from connecting to the same wiimote twice.
- // (And disallows using wiimotes in use by other programs)
- // This is what "WiiYourself" does.
- // Apparently this doesn't work for everyone. It might be their fault.
- auto const open_flags = FILE_SHARE_READ;
-#endif
-
- m_dev_handle = CreateFile(m_devicepath.c_str(),
- GENERIC_READ | GENERIC_WRITE, open_flags,
- nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
-
- if (m_dev_handle == INVALID_HANDLE_VALUE)
- {
- m_dev_handle = 0;
- return false;
- }
-
-#if 0
- TCHAR name[128] = {};
- pHidD_GetProductString(dev_handle, name, 128);
-
- //ERROR_LOG(WIIMOTE, "Product string: %s", TStrToUTF8(name).c_str());
-
- if (!IsValidBluetoothName(TStrToUTF8(name)))
- {
- CloseHandle(dev_handle);
- dev_handle = 0;
- return false;
- }
-#endif
-
-#if 0
- HIDD_ATTRIBUTES attr;
- attr.Size = sizeof(attr);
- if (!pHidD_GetAttributes(dev_handle, &attr))
- {
- CloseHandle(dev_handle);
- dev_handle = 0;
- return false;
- }
-#endif
-
- // TODO: thread isn't started here now, do this elsewhere
- // This isn't as drastic as it sounds, since the process in which the threads
- // reside is normal priority. Needed for keeping audio reports at a decent rate
-/*
- if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
- {
- ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority");
- }
-*/
-#ifdef SHARE_WRITE_WIIMOTES
- g_connected_wiimotes.insert(m_devicepath);
-#endif
-
- return true;
-}
-
-void WiimoteWindows::DisconnectInternal()
-{
- if (!IsConnected())
- return;
-
- CloseHandle(m_dev_handle);
- m_dev_handle = 0;
-
-#ifdef SHARE_WRITE_WIIMOTES
- std::lock_guard lk(g_connected_wiimotes_lock);
- g_connected_wiimotes.erase(m_devicepath);
-#endif
-}
-
-WiimoteWindows::WiimoteWindows(const std::basic_string& path) : m_devicepath(path)
-{
- m_dev_handle = 0;
- m_stack = MSBT_STACK_UNKNOWN;
-
- m_hid_overlap_read = OVERLAPPED();
- m_hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr);
-
- m_hid_overlap_write = OVERLAPPED();
- m_hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr);
-}
-
-WiimoteWindows::~WiimoteWindows()
-{
- Shutdown();
- CloseHandle(m_hid_overlap_read.hEvent);
- CloseHandle(m_hid_overlap_write.hEvent);
-}
-
-bool WiimoteWindows::IsConnected() const
-{
- return m_dev_handle != 0;
-}
-
-// positive = read packet
-// negative = didn't read packet
-// zero = error
-int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index)
-{
- // Add data report indicator byte (here, 0xa1)
- buf[0] = 0xa1;
- // Used below for a warning
- buf[1] = 0;
-
- DWORD bytes = 0;
- ResetEvent(hid_overlap_read.hEvent);
- if (!ReadFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
- {
- auto const read_err = GetLastError();
-
- if (ERROR_IO_PENDING == read_err)
- {
- auto const wait_result = WaitForSingleObject(hid_overlap_read.hEvent, INFINITE);
-
- // In case the event was signalled by IOWakeup before the read completed, cancel it.
- CancelIo(dev_handle);
-
- if (WAIT_FAILED == wait_result)
- {
- WARN_LOG(WIIMOTE, "A wait error occurred on reading from Wiimote %i.", index + 1);
- }
-
- if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, FALSE))
- {
- auto const overlapped_err = GetLastError();
-
- if (ERROR_OPERATION_ABORTED == overlapped_err)
- {
- // It was.
- return -1;
- }
-
- WARN_LOG(WIIMOTE, "GetOverlappedResult error %d on Wiimote %i.", overlapped_err, index + 1);
- return 0;
- }
- }
- else
- {
- WARN_LOG(WIIMOTE, "ReadFile error %d on Wiimote %i.", read_err, index + 1);
- return 0;
- }
- }
-
- return bytes + 1;
-}
-
-void WiimoteWindows::IOWakeup()
-{
- SetEvent(m_hid_overlap_read.hEvent);
-}
-
-
-// positive = read packet
-// negative = didn't read packet
-// zero = error
-int WiimoteWindows::IORead(u8* buf)
-{
- return _IORead(m_dev_handle, m_hid_overlap_read, buf, m_index);
-}
-
-
-int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len, DWORD* written)
-{
- switch (stack)
- {
- case MSBT_STACK_UNKNOWN:
- {
- // Try to auto-detect the stack type
- stack = MSBT_STACK_BLUESOLEIL;
- if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, len, written))
- return 1;
-
- stack = MSBT_STACK_MS;
- if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, len, written))
- return 1;
-
- stack = MSBT_STACK_UNKNOWN;
- break;
- }
- case MSBT_STACK_MS:
- {
- auto result = pHidD_SetOutputReport(dev_handle, const_cast(buf) + 1, (ULONG)(len - 1));
- //FlushFileBuffers(dev_handle);
-
- if (!result)
- {
- auto err = GetLastError();
- if (err == 121)
- {
- // Semaphore timeout
- NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to the Wiimote");
- }
- else if (err != 0x1F) // Some third-party adapters (DolphinBar) use this
- // error code to signal the absence of a WiiMote
- // linked to the HID device.
- {
- WARN_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
- }
- }
-
- if (written)
- *written = (result ? (DWORD)len : 0);
-
- return result;
- }
- case MSBT_STACK_BLUESOLEIL:
- {
- u8 big_buf[MAX_PAYLOAD];
- if (len < MAX_PAYLOAD)
- {
- std::copy(buf, buf + len, big_buf);
- std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
- buf = big_buf;
- }
-
- ResetEvent(hid_overlap_write.hEvent);
- DWORD bytes = 0;
- if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write))
- {
- // If the number of written bytes is requested, block until we can provide
- // this information to the called.
- if (written)
- {
- auto const wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
- if (WAIT_TIMEOUT == wait_result)
- {
- WARN_LOG(WIIMOTE, "_IOWrite: A timeout occurred on writing to Wiimote.");
- CancelIo(dev_handle);
- *written = 0;
- }
- else if (WAIT_FAILED == wait_result)
- {
- WARN_LOG(WIIMOTE, "_IOWrite: A wait error occurred on writing to Wiimote.");
- CancelIo(dev_handle);
- *written = 0;
- }
- else if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE))
- *written = 0;
- }
- return 1;
- }
- else
- {
- auto const err = GetLastError();
- if (ERROR_IO_PENDING == err)
- {
- CancelIo(dev_handle);
- }
- return 0;
- }
- }
- }
-
- return 0;
-}
-
-int WiimoteWindows::IOWrite(const u8* buf, size_t len)
-{
- return _IOWrite(m_dev_handle, m_hid_overlap_write, m_stack, buf, len, nullptr);
-}
-
-// invokes callback for each found wiimote bluetooth device
-template
-void ProcessWiimotes(bool new_scan, T& callback)
-{
- BLUETOOTH_DEVICE_SEARCH_PARAMS srch;
- srch.dwSize = sizeof(srch);
- srch.fReturnAuthenticated = true;
- srch.fReturnRemembered = true;
- // Does not filter properly somehow, so we need to do an additional check on
- // fConnected BT Devices
- srch.fReturnConnected = true;
- srch.fReturnUnknown = true;
- srch.fIssueInquiry = new_scan;
- // multiple of 1.28 seconds
- srch.cTimeoutMultiplier = 2;
-
- BLUETOOTH_FIND_RADIO_PARAMS radioParam;
- radioParam.dwSize = sizeof(radioParam);
-
- HANDLE hRadio;
-
- // TODO: save radio(s) in the WiimoteScanner constructor?
-
- // Enumerate BT radios
- HBLUETOOTH_RADIO_FIND hFindRadio = pBluetoothFindFirstRadio(&radioParam, &hRadio);
- while (hFindRadio)
- {
- BLUETOOTH_RADIO_INFO radioInfo;
- radioInfo.dwSize = sizeof(radioInfo);
-
- auto const rinfo_result = pBluetoothGetRadioInfo(hRadio, &radioInfo);
- if (ERROR_SUCCESS == rinfo_result)
- {
- srch.hRadio = hRadio;
-
- BLUETOOTH_DEVICE_INFO btdi;
- btdi.dwSize = sizeof(btdi);
-
- // Enumerate BT devices
- HBLUETOOTH_DEVICE_FIND hFindDevice = pBluetoothFindFirstDevice(&srch, &btdi);
- while (hFindDevice)
- {
- // btdi.szName is sometimes missing it's content - it's a bt feature..
- DEBUG_LOG(WIIMOTE, "Authenticated %i connected %i remembered %i ",
- btdi.fAuthenticated, btdi.fConnected, btdi.fRemembered);
-
- if (IsValidBluetoothName(UTF16ToUTF8(btdi.szName)))
- {
- callback(hRadio, radioInfo, btdi);
- }
-
- if (false == pBluetoothFindNextDevice(hFindDevice, &btdi))
- {
- pBluetoothFindDeviceClose(hFindDevice);
- hFindDevice = nullptr;
- }
- }
- }
-
- if (false == pBluetoothFindNextRadio(hFindRadio, &hRadio))
- {
- pBluetoothFindRadioClose(hFindRadio);
- hFindRadio = nullptr;
- }
- }
-}
-
-void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
-{
- //if (btdi.fConnected)
- {
- if (SUCCEEDED(pBluetoothRemoveDevice(&btdi.Address)))
- {
- NOTICE_LOG(WIIMOTE, "Removed BT Device", GetLastError());
- }
- }
-}
-
-bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
-{
- // We don't want "remembered" devices.
- // SetServiceState will just fail with them..
- if (!btdi.fConnected && !btdi.fRemembered)
- {
- auto const& wm_addr = btdi.Address.rgBytes;
-
- NOTICE_LOG(WIIMOTE, "Found Wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.",
- wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]);
-
-#if defined(AUTHENTICATE_WIIMOTES)
- // Authenticate
- auto const& radio_addr = radio_info.address.rgBytes;
- // FIXME Not sure this usage of OOB_DATA_INFO is correct...
- BLUETOOTH_OOB_DATA_INFO oob_data_info = { 0 };
- memcpy(&oob_data_info.C[0], &radio_addr[0], sizeof(WCHAR) * 6);
- const DWORD auth_result = pBluetoothAuthenticateDeviceEx(nullptr, hRadio, &btdi,
- &oob_data_info, MITMProtectionNotDefined);
-
- if (ERROR_SUCCESS != auth_result)
- {
- ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothAuthenticateDeviceEx returned %08x", auth_result);
- }
-
- DWORD pcServices = 16;
- GUID guids[16];
- // If this is not done, the Wii device will not remember the pairing
- const DWORD srv_result = pBluetoothEnumerateInstalledServices(hRadio, &btdi, &pcServices, guids);
-
- if (ERROR_SUCCESS != srv_result)
- {
- ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothEnumerateInstalledServices returned %08x", srv_result);
- }
-#endif
- // Activate service
- const DWORD hr = pBluetoothSetServiceState(hRadio, &btdi,
- &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
-
- g_connect_times[btdi.Address.ullLong] = std::time(nullptr);
-
- if (FAILED(hr))
- {
- ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothSetServiceState returned %08x", hr);
- }
- else
- {
- return true;
- }
- }
-
- return false;
-}
-
-// Removes remembered non-connected devices
-bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
-{
- if (!btdi.fConnected && btdi.fRemembered)
- {
- // Time to avoid RemoveDevice after SetServiceState.
- // Sometimes SetServiceState takes a while..
- auto const avoid_forget_seconds = 5.0;
-
- auto pair_time = g_connect_times.find(btdi.Address.ullLong);
- if (pair_time == g_connect_times.end() ||
- std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds)
- {
- // Make Windows forget about device so it will re-find it if visible.
- // This is also required to detect a disconnect for some reason..
- NOTICE_LOG(WIIMOTE, "Removing remembered Wiimote.");
- pBluetoothRemoveDevice(&btdi.Address);
- return true;
- }
- }
-
- return false;
-}
-
-};
diff --git a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm
deleted file mode 100644
index 9e00d946c8..0000000000
--- a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm
+++ /dev/null
@@ -1,380 +0,0 @@
-#define BLUETOOTH_VERSION_USE_CURRENT
-
-#include "Common/Common.h"
-#include "Core/HW/WiimoteReal/WiimoteReal.h"
-
-@interface SearchBT: NSObject {
-@public
- unsigned int maxDevices;
- bool done;
-}
-@end
-
-@interface ConnectBT: NSObject {}
-@end
-
-namespace WiimoteReal
-{
-
-class WiimoteDarwin final : public Wiimote
-{
-public:
- WiimoteDarwin(IOBluetoothDevice* device);
- ~WiimoteDarwin() override;
-
- // These are not protected/private because ConnectBT needs them.
- void DisconnectInternal() override;
- IOBluetoothDevice* m_btd;
- unsigned char* m_input;
- int m_inputlen;
-
-protected:
- bool ConnectInternal() override;
- bool IsConnected() const override;
- void IOWakeup() override;
- int IORead(u8* buf) override;
- int IOWrite(u8 const* buf, size_t len) override;
- void EnablePowerAssertionInternal() override;
- void DisablePowerAssertionInternal() override;
-
-private:
- IOBluetoothL2CAPChannel* m_ichan;
- IOBluetoothL2CAPChannel* m_cchan;
- bool m_connected;
- CFRunLoopRef m_wiimote_thread_run_loop;
- IOPMAssertionID m_pm_assertion;
-};
-
-WiimoteScanner::WiimoteScanner()
- : m_run_thread()
- , m_want_wiimotes()
-{}
-
-WiimoteScanner::~WiimoteScanner()
-{}
-
-void WiimoteScanner::Update()
-{}
-
-void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board)
-{
- // TODO: find the device in the constructor and save it for later
- IOBluetoothHostController *bth;
- IOBluetoothDeviceInquiry *bti;
- SearchBT *sbt;
- NSEnumerator *en;
- found_board = nullptr;
-
- bth = [[IOBluetoothHostController alloc] init];
- if ([bth addressAsString] == nil)
- {
- WARN_LOG(WIIMOTE, "No bluetooth host controller");
- [bth release];
- return;
- }
-
- sbt = [[SearchBT alloc] init];
- sbt->maxDevices = 32;
- bti = [[IOBluetoothDeviceInquiry alloc] init];
- [bti setDelegate: sbt];
- [bti setInquiryLength: 2];
-
- if ([bti start] != kIOReturnSuccess)
- {
- ERROR_LOG(WIIMOTE, "Unable to do bluetooth discovery");
- [bth release];
- [sbt release];
- return;
- }
-
- do
- {
- CFRunLoopRun();
- }
- while (!sbt->done);
-
- int found_devices = [[bti foundDevices] count];
-
- if (found_devices)
- NOTICE_LOG(WIIMOTE, "Found %i bluetooth devices", found_devices);
-
- en = [[bti foundDevices] objectEnumerator];
- for (int i = 0; i < found_devices; i++)
- {
- IOBluetoothDevice *dev = [en nextObject];
- if (!IsValidBluetoothName([[dev name] UTF8String]))
- continue;
-
- Wiimote* wm = new WiimoteDarwin([dev retain]);
-
- if (IsBalanceBoardName([[dev name] UTF8String]))
- {
- found_board = wm;
- }
- else
- {
- found_wiimotes.push_back(wm);
- }
- }
-
- [bth release];
- [bti release];
- [sbt release];
-}
-
-bool WiimoteScanner::IsReady() const
-{
- // TODO: only return true when a BT device is present
- return true;
-}
-
-WiimoteDarwin::WiimoteDarwin(IOBluetoothDevice* device) : m_btd(device)
-{
- m_inputlen = 0;
- m_connected = false;
- m_wiimote_thread_run_loop = nullptr;
- m_pm_assertion = kIOPMNullAssertionID;
-}
-
-WiimoteDarwin::~WiimoteDarwin()
-{
- Shutdown();
- if (m_wiimote_thread_run_loop)
- {
- CFRelease(m_wiimote_thread_run_loop);
- m_wiimote_thread_run_loop = nullptr;
- }
- [m_btd release];
- m_btd = nil;
- DisablePowerAssertionInternal();
-}
-
-// Connect to a wiimote with a known address.
-bool WiimoteDarwin::ConnectInternal()
-{
- if (IsConnected())
- return false;
-
- ConnectBT *cbt = [[ConnectBT alloc] init];
-
- m_cchan = m_ichan = nil;
-
- IOReturn ret = [m_btd openConnection];
- if (ret)
- {
- ERROR_LOG(WIIMOTE, "Unable to open Bluetooth connection to wiimote %i: %x",
- m_index + 1, ret);
- [cbt release];
- return false;
- }
-
- ret = [m_btd openL2CAPChannelSync: &m_cchan
- withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
- if (ret)
- {
- ERROR_LOG(WIIMOTE, "Unable to open control channel for wiimote %i: %x",
- m_index + 1, ret);
- goto bad;
- }
- // Apple docs claim:
- // "The L2CAP channel object is already retained when this function returns
- // success; the channel must be released when the caller is done with it."
- // But without this, the channels get over-autoreleased, even though the
- // refcounting behavior here is clearly correct.
- [m_cchan retain];
-
- ret = [m_btd openL2CAPChannelSync: &m_ichan
- withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
- if (ret)
- {
- WARN_LOG(WIIMOTE, "Unable to open interrupt channel for wiimote %i: %x",
- m_index + 1, ret);
- goto bad;
- }
- [m_ichan retain];
-
- NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s",
- m_index + 1, [[m_btd addressString] UTF8String]);
-
- m_connected = true;
-
- [cbt release];
-
- m_wiimote_thread_run_loop = (CFRunLoopRef) CFRetain(CFRunLoopGetCurrent());
-
- return true;
-
-bad:
- DisconnectInternal();
- [cbt release];
- return false;
-}
-
-// Disconnect a wiimote.
-void WiimoteDarwin::DisconnectInternal()
-{
- [m_ichan closeChannel];
- [m_ichan release];
- m_ichan = nil;
-
- [m_cchan closeChannel];
- [m_cchan release];
- m_cchan = nil;
-
- [m_btd closeConnection];
-
- if (!IsConnected())
- return;
-
- NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", m_index + 1);
-
- m_connected = false;
-}
-
-bool WiimoteDarwin::IsConnected() const
-{
- return m_connected;
-}
-
-void WiimoteDarwin::IOWakeup()
-{
- if (m_wiimote_thread_run_loop)
- {
- CFRunLoopStop(m_wiimote_thread_run_loop);
- }
-}
-
-int WiimoteDarwin::IORead(unsigned char *buf)
-{
- m_input = buf;
- m_inputlen = -1;
-
- CFRunLoopRun();
-
- return m_inputlen;
-}
-
-int WiimoteDarwin::IOWrite(const unsigned char *buf, size_t len)
-{
- IOReturn ret;
-
- if (!IsConnected())
- return 0;
-
- ret = [m_ichan writeAsync: const_cast((void *)buf) length: (int)len refcon: nil];
-
- if (ret == kIOReturnSuccess)
- return len;
- else
- return 0;
-}
-
-void WiimoteDarwin::EnablePowerAssertionInternal()
-{
- if (m_pm_assertion == kIOPMNullAssertionID)
- {
- if (IOReturn ret = IOPMAssertionCreateWithName(kIOPMAssertPreventUserIdleDisplaySleep, kIOPMAssertionLevelOn, CFSTR("Dolphin Wiimote activity"), &m_pm_assertion))
- ERROR_LOG(WIIMOTE, "Could not create power management assertion: %08x", ret);
- }
-}
-
-void WiimoteDarwin::DisablePowerAssertionInternal()
-{
- if (m_pm_assertion != kIOPMNullAssertionID)
- {
- if (IOReturn ret = IOPMAssertionRelease(m_pm_assertion))
- ERROR_LOG(WIIMOTE, "Could not release power management assertion: %08x", ret);
- }
-}
-
-} // namespace
-
-@implementation SearchBT
-- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender
- error: (IOReturn) error
- aborted: (BOOL) aborted
-{
- done = true;
- CFRunLoopStop(CFRunLoopGetCurrent());
-}
-
-- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry *) sender
- device: (IOBluetoothDevice *) device
-{
- NOTICE_LOG(WIIMOTE, "Discovered bluetooth device at %s: %s",
- [[device addressString] UTF8String],
- [[device name] UTF8String]);
-
- if ([[sender foundDevices] count] == maxDevices)
- [sender stop];
-}
-@end
-
-@implementation ConnectBT
-- (void) l2capChannelData: (IOBluetoothL2CAPChannel *) l2capChannel
- data: (unsigned char *) data
- length: (NSUInteger) length
-{
- IOBluetoothDevice *device = [l2capChannel device];
- WiimoteReal::WiimoteDarwin *wm = nullptr;
-
- std::lock_guard lk(WiimoteReal::g_refresh_lock);
-
- for (int i = 0; i < MAX_WIIMOTES; i++)
- {
- if (WiimoteReal::g_wiimotes[i] == nullptr)
- continue;
- wm = static_cast(WiimoteReal::g_wiimotes[i]);
- if ([device isEqual: wm->m_btd] != TRUE)
- wm = nullptr;
- }
-
- if (wm == nullptr) {
- ERROR_LOG(WIIMOTE, "Received packet for unknown wiimote");
- return;
- }
-
- if (length > MAX_PAYLOAD) {
- WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, too large",
- wm->m_index + 1);
- return;
- }
-
- if (wm->m_inputlen != -1) {
- WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full",
- wm->m_index + 1);
- return;
- }
-
- memcpy(wm->m_input, data, length);
- wm->m_inputlen = length;
-
- CFRunLoopStop(CFRunLoopGetCurrent());
-}
-
-- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel
-{
- IOBluetoothDevice *device = [l2capChannel device];
- WiimoteReal::WiimoteDarwin *wm = nullptr;
-
- std::lock_guard lk(WiimoteReal::g_refresh_lock);
-
- for (int i = 0; i < MAX_WIIMOTES; i++)
- {
- if (WiimoteReal::g_wiimotes[i] == nullptr)
- continue;
- wm = static_cast(WiimoteReal::g_wiimotes[i]);
- if ([device isEqual: wm->m_btd] != TRUE)
- wm = nullptr;
- }
-
- if (wm == nullptr) {
- ERROR_LOG(WIIMOTE, "Channel for unknown wiimote was closed");
- return;
- }
-
- WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->m_index + 1);
-
- wm->DisconnectInternal();
-}
-@end
diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
new file mode 100644
index 0000000000..5e695d5f42
--- /dev/null
+++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
@@ -0,0 +1,150 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include
+
+#include "Common/Common.h"
+#include "Core/HW/WiimoteReal/WiimoteReal.h"
+
+namespace WiimoteReal
+{
+
+class WiimoteHidapi final : public Wiimote
+{
+public:
+ WiimoteHidapi(char* device_path);
+ ~WiimoteHidapi() override;
+
+protected:
+ bool ConnectInternal() override;
+ void DisconnectInternal() override;
+ bool IsConnected() const override;
+ void IOWakeup() override;
+ int IORead(u8* buf) override;
+ int IOWrite(u8 const* buf, size_t len) override;
+
+private:
+ std::string m_device_path;
+ hid_device* m_handle;
+};
+
+WiimoteScanner::WiimoteScanner()
+ : m_want_wiimotes()
+{
+ if (hid_init() == -1)
+ {
+ ERROR_LOG(WIIMOTE, "Failed to initialize hidapi.");
+ }
+}
+
+bool WiimoteScanner::IsReady() const
+{
+ return true;
+}
+
+WiimoteScanner::~WiimoteScanner()
+{
+ if (hid_exit() == -1)
+ {
+ ERROR_LOG(WIIMOTE, "Failed to clean up hidapi.");
+ }
+}
+
+void WiimoteScanner::Update()
+{}
+
+void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board)
+{
+ // Search for both old and new Wiimotes.
+ for (uint16_t product_id : {0x0306, 0x0330})
+ {
+ hid_device_info* list = hid_enumerate(0x057e, product_id);
+ hid_device_info* item = list;
+ while (item)
+ {
+ NOTICE_LOG(WIIMOTE, "Found Wiimote at %s: %ls %ls", item->path, item->manufacturer_string, item->product_string);
+ Wiimote* wiimote = new WiimoteHidapi(item->path);
+ found_wiimotes.push_back(wiimote);
+ item = item->next;
+ }
+ hid_free_enumeration(list);
+ }
+}
+
+WiimoteHidapi::WiimoteHidapi(char* device_path) : m_device_path(device_path), m_handle(nullptr)
+{}
+
+WiimoteHidapi::~WiimoteHidapi()
+{
+ Shutdown();
+}
+
+// Connect to a wiimote with a known address.
+bool WiimoteHidapi::ConnectInternal()
+{
+ m_handle = hid_open_path(m_device_path.c_str());
+ if (!m_handle)
+ {
+ ERROR_LOG(WIIMOTE, "Could not connect to Wiimote at \"%s\". "
+ "Do you have permission to access the device?", m_device_path.c_str());
+ }
+ return !!m_handle;
+}
+
+void WiimoteHidapi::DisconnectInternal()
+{
+ hid_close(m_handle);
+ m_handle = nullptr;
+}
+
+bool WiimoteHidapi::IsConnected() const
+{
+ return !!m_handle;
+}
+
+void WiimoteHidapi::IOWakeup()
+{}
+
+// positive = read packet
+// negative = didn't read packet
+// zero = error
+int WiimoteHidapi::IORead(u8* buf)
+{
+ int timeout = 200; // ms
+ int result = hid_read_timeout(m_handle, buf + 1, MAX_PAYLOAD - 1, timeout);
+ // TODO: If and once we use hidapi across plaforms, change our internal API to clean up this mess.
+ if (result == -1)
+ {
+ ERROR_LOG(WIIMOTE, "Failed to read from %s.", m_device_path.c_str());
+ result = 0;
+ }
+ else if (result == 0)
+ {
+ result = -1;
+ }
+ else
+ {
+ buf[0] = WM_SET_REPORT | WM_BT_INPUT;
+ result += 1;
+ }
+ return result;
+}
+
+int WiimoteHidapi::IOWrite(u8 const* buf, size_t len)
+{
+ _dbg_assert_(WIIMOTE, buf[0] == (WM_SET_REPORT | WM_BT_OUTPUT));
+ int result = hid_write(m_handle, buf + 1, len - 1);
+ if (result == -1)
+ {
+ ERROR_LOG(WIIMOTE, "Failed to write to %s.", m_device_path.c_str());
+ result = 0;
+ }
+ else
+ {
+ result += 1;
+ }
+ return result;
+}
+
+}; // WiimoteReal
diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h
index b7edb53d72..84fad33adb 100644
--- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h
+++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h
@@ -135,13 +135,6 @@ private:
volatile bool m_run_thread;
volatile bool m_want_wiimotes;
volatile bool m_want_bb;
-
-#if defined(_WIN32)
- void CheckDeviceType(std::basic_string &devicepath, bool &real_wiimote, bool &is_bb);
-#elif defined(__linux__) && HAVE_BLUEZ
- int device_id;
- int device_sock;
-#endif
};
extern std::recursive_mutex g_refresh_lock;
diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h
index 847720ba98..ee056e2d87 100644
--- a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h
+++ b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h
@@ -4,22 +4,6 @@
#pragma once
-#ifdef _WIN32
- #include
-#elif defined(__APPLE__)
- // Work around an Apple bug: for some reason, IOBluetooth.h errors on
- // inclusion in Mavericks, but only in Objective-C++ C++11 mode. I filed
- // this as ; in the meantime...
- #import
- #undef NS_ENUM_AVAILABLE
- #define NS_ENUM_AVAILABLE(...)
- // end hack
- #import
- #include
-#elif defined(__linux__) && HAVE_BLUEZ
- #include
-#endif
-
// Wiimote internal codes
// Communication channels