From e0aa15610b401e359e664974df32569e029815d7 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 15 Dec 2017 13:35:54 -1000 Subject: [PATCH] macOS IOKit interface fixes; callback-change mutex for controllers --- include/boo/inputdev/DeviceBase.hpp | 20 ++++++++++++++++++-- include/boo/inputdev/DeviceFinder.hpp | 2 +- include/boo/inputdev/DolphinSmashAdapter.hpp | 10 +++++++--- include/boo/inputdev/DualshockPad.hpp | 5 +---- include/boo/inputdev/GenericPad.hpp | 4 +--- include/boo/inputdev/NintendoPowerA.hpp | 5 +---- include/boo/inputdev/XInputPad.hpp | 7 +++---- lib/inputdev/DeviceBase.cpp | 4 ---- lib/inputdev/DolphinSmashAdapter.cpp | 19 +++++++++++++++---- lib/inputdev/DualshockPad.cpp | 11 +++++++---- lib/inputdev/GenericPad.cpp | 17 ++++++++++------- lib/inputdev/HIDDeviceIOKit.cpp | 13 +++++++------ lib/inputdev/HIDListenerIOKit.cpp | 17 ++++++++++++----- lib/inputdev/HIDListenerWinUSB.cpp | 1 + lib/inputdev/NintendoPowerA.cpp | 4 +++- 15 files changed, 87 insertions(+), 52 deletions(-) diff --git a/include/boo/inputdev/DeviceBase.hpp b/include/boo/inputdev/DeviceBase.hpp index c358e31..638f479 100644 --- a/include/boo/inputdev/DeviceBase.hpp +++ b/include/boo/inputdev/DeviceBase.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "boo/System.hpp" #if _WIN32 @@ -33,10 +34,10 @@ class DeviceBase : public std::enable_shared_from_this class DeviceToken* m_token; std::shared_ptr m_hidDev; void _deviceDisconnected(); - + public: DeviceBase(DeviceToken* token); - virtual ~DeviceBase(); + virtual ~DeviceBase() = default; void closeDevice(); /* Callbacks */ @@ -63,6 +64,21 @@ public: virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/, uint32_t /*message*/) {} }; +template +class TDeviceBase : public DeviceBase +{ +protected: + std::mutex m_callbackLock; + CB* m_callback = nullptr; +public: + TDeviceBase(DeviceToken* token) : DeviceBase(token) {} + void setCallback(CB* cb) + { + std::lock_guard lk(m_callbackLock); + m_callback = cb; + } +}; + } #endif // CDEVICEBASE diff --git a/include/boo/inputdev/DeviceFinder.hpp b/include/boo/inputdev/DeviceFinder.hpp index 97229cc..2472d32 100644 --- a/include/boo/inputdev/DeviceFinder.hpp +++ b/include/boo/inputdev/DeviceFinder.hpp @@ -112,7 +112,7 @@ public: } } } - ~DeviceFinder() + virtual ~DeviceFinder() { if (m_listener) m_listener->stopScanning(); diff --git a/include/boo/inputdev/DolphinSmashAdapter.hpp b/include/boo/inputdev/DolphinSmashAdapter.hpp index b199d02..27d6941 100644 --- a/include/boo/inputdev/DolphinSmashAdapter.hpp +++ b/include/boo/inputdev/DolphinSmashAdapter.hpp @@ -60,9 +60,10 @@ struct IDolphinSmashAdapterCallback const DolphinControllerState& state) {(void)idx;(void)type;(void)state;} }; -class DolphinSmashAdapter final : public DeviceBase +class DolphinSmashAdapter final : public TDeviceBase { - IDolphinSmashAdapterCallback* m_callback = nullptr; + int16_t m_leftStickCal[2] = {0x7f}; + int16_t m_rightStickCal[2] = {0x7f}; uint8_t m_knownControllers = 0; uint8_t m_rumbleRequest = 0; bool m_hardStop[4] = {false}; @@ -76,7 +77,10 @@ public: ~DolphinSmashAdapter(); void setCallback(IDolphinSmashAdapterCallback* cb) - {m_callback = cb; m_knownControllers = 0;} + { + TDeviceBase::setCallback(cb); + m_knownControllers = 0; + } void startRumble(unsigned idx) {if (idx >= 4) return; m_rumbleRequest |= 1< { - IDualshockPadCallback* m_callback; EDualshockMotor m_rumbleRequest; EDualshockMotor m_rumbleState; uint8_t m_rumbleDuration[2]; @@ -140,8 +139,6 @@ public: DualshockPad(DeviceToken* token); ~DualshockPad(); - void setCallback(IDualshockPadCallback* cb) { m_callback = cb; } - void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity=255) { m_rumbleRequest |= motor; diff --git a/include/boo/inputdev/GenericPad.hpp b/include/boo/inputdev/GenericPad.hpp index 0fde410..852279e 100644 --- a/include/boo/inputdev/GenericPad.hpp +++ b/include/boo/inputdev/GenericPad.hpp @@ -16,15 +16,13 @@ struct IGenericPadCallback virtual void valueUpdate(const HIDMainItem& item, int32_t value) {} }; -class GenericPad final : public DeviceBase +class GenericPad final : public TDeviceBase { HIDParser m_parser; - IGenericPadCallback* m_cb = nullptr; public: GenericPad(DeviceToken* token); ~GenericPad(); - void setCallback(IGenericPadCallback* cb) { m_cb = cb; } void deviceDisconnected(); void initialCycle(); void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); diff --git a/include/boo/inputdev/NintendoPowerA.hpp b/include/boo/inputdev/NintendoPowerA.hpp index e5d46b6..83ca8ae 100644 --- a/include/boo/inputdev/NintendoPowerA.hpp +++ b/include/boo/inputdev/NintendoPowerA.hpp @@ -37,9 +37,8 @@ struct INintendoPowerACallback virtual void controllerUpdate(const NintendoPowerAState& state) {} }; -class NintendoPowerA final : public DeviceBase +class NintendoPowerA final : public TDeviceBase { - INintendoPowerACallback* m_callback = nullptr; NintendoPowerAState m_last; void deviceDisconnected(); void initialCycle(); @@ -49,8 +48,6 @@ class NintendoPowerA final : public DeviceBase public: NintendoPowerA(DeviceToken*); ~NintendoPowerA(); - - void setCallback(INintendoPowerACallback* cb) { m_callback = cb; } }; } diff --git a/include/boo/inputdev/XInputPad.hpp b/include/boo/inputdev/XInputPad.hpp index 8c5a275..88ac528 100644 --- a/include/boo/inputdev/XInputPad.hpp +++ b/include/boo/inputdev/XInputPad.hpp @@ -33,17 +33,16 @@ struct IXInputPadCallback virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {} }; -class XInputPad final : public DeviceBase +class XInputPad final : public TDeviceBase { friend class HIDListenerWinUSB; - IXInputPadCallback* m_callback; uint16_t m_rumbleRequest[2] = {}; uint16_t m_rumbleState[2] = {}; public: - XInputPad(DeviceToken* token) : DeviceBase(token) {} - void setCallback(IXInputPadCallback* cb) { m_callback = cb; } + XInputPad(DeviceToken* token) : TDeviceBase(token) {} void deviceDisconnected() { + std::lock_guard lk(m_callbackLock); if (m_callback) m_callback->controllerDisconnected(); } diff --git a/lib/inputdev/DeviceBase.cpp b/lib/inputdev/DeviceBase.cpp index 5c7b308..9c33fae 100644 --- a/lib/inputdev/DeviceBase.cpp +++ b/lib/inputdev/DeviceBase.cpp @@ -11,10 +11,6 @@ DeviceBase::DeviceBase(DeviceToken* token) { } -DeviceBase::~DeviceBase() -{ -} - void DeviceBase::_deviceDisconnected() { deviceDisconnected(); diff --git a/lib/inputdev/DolphinSmashAdapter.cpp b/lib/inputdev/DolphinSmashAdapter.cpp index 4dba489..c6522ef 100644 --- a/lib/inputdev/DolphinSmashAdapter.cpp +++ b/lib/inputdev/DolphinSmashAdapter.cpp @@ -8,7 +8,7 @@ namespace boo * Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c */ -DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) : DeviceBase(token) {} +DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) : TDeviceBase(token) {} DolphinSmashAdapter::~DolphinSmashAdapter() {} @@ -61,6 +61,7 @@ void DolphinSmashAdapter::transferCycle() // printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]); + std::lock_guard lk(m_callbackLock); if (!m_callback) return; @@ -74,6 +75,10 @@ void DolphinSmashAdapter::transferCycle() EDolphinControllerType type = parseState(&state, controller, rumble); if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i)) { + m_leftStickCal[0] = reinterpret_cast(state.m_leftStick[0]); + m_leftStickCal[1] = reinterpret_cast(state.m_leftStick[1]); + m_rightStickCal[0] = reinterpret_cast(state.m_rightStick[0]); + m_rightStickCal[1] = reinterpret_cast(state.m_rightStick[1]); m_knownControllers |= 1 << i; m_callback->controllerConnected(i, type); } @@ -83,7 +88,13 @@ void DolphinSmashAdapter::transferCycle() m_callback->controllerDisconnected(i); } if (m_knownControllers & 1 << i) + { + state.m_leftStick[0] = int8_t(reinterpret_cast(state.m_leftStick[0]) - m_leftStickCal[0]); + state.m_leftStick[1] = int8_t(reinterpret_cast(state.m_leftStick[1]) - m_leftStickCal[1]); + state.m_rightStick[0] = int8_t(reinterpret_cast(state.m_rightStick[0]) - m_rightStickCal[0]); + state.m_rightStick[1] = int8_t(reinterpret_cast(state.m_rightStick[1]) - m_rightStickCal[1]); m_callback->controllerUpdate(i, type, state); + } rumbleMask |= rumble ? 1 << i : 0; } @@ -115,14 +126,14 @@ void DolphinSmashAdapter::finalCycle() void DolphinSmashAdapter::deviceDisconnected() { - if (!m_callback) - return; for (uint32_t i = 0; i < 4; i++) { if (m_knownControllers & 1 << i) { m_knownControllers &= ~(1 << i); - m_callback->controllerDisconnected(i); + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(i); } } } diff --git a/lib/inputdev/DualshockPad.cpp b/lib/inputdev/DualshockPad.cpp index 918808b..db37873 100644 --- a/lib/inputdev/DualshockPad.cpp +++ b/lib/inputdev/DualshockPad.cpp @@ -29,8 +29,7 @@ static const uint8_t defaultReport[49] = { }; DualshockPad::DualshockPad(DeviceToken* token) - : DeviceBase(token), - m_callback(nullptr), + : TDeviceBase(token), m_rumbleRequest(EDualshockMotor::None), m_rumbleState(EDualshockMotor::None) { @@ -44,6 +43,7 @@ DualshockPad::~DualshockPad() void DualshockPad::deviceDisconnected() { + std::lock_guard lk(m_callbackLock); if (m_callback) m_callback->controllerDisconnected(); } @@ -95,8 +95,11 @@ void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDRepo state.accYaw = (atan2(accXval, accZval) + M_PI) * RAD_TO_DEG; state.gyroZ = (state.m_gyrometerZ / 1023.f); - if (m_callback) - m_callback->controllerUpdate(*this, state); + { + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerUpdate(*this, state); + } if (m_rumbleRequest != m_rumbleState) { diff --git a/lib/inputdev/GenericPad.cpp b/lib/inputdev/GenericPad.cpp index 1329b7f..84f73fb 100644 --- a/lib/inputdev/GenericPad.cpp +++ b/lib/inputdev/GenericPad.cpp @@ -5,7 +5,7 @@ namespace boo { GenericPad::GenericPad(DeviceToken* token) -: DeviceBase(token) +: TDeviceBase(token) { } @@ -14,8 +14,9 @@ GenericPad::~GenericPad() {} void GenericPad::deviceDisconnected() { - if (m_cb) - m_cb->controllerDisconnected(); + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(); } void GenericPad::initialCycle() @@ -29,18 +30,20 @@ void GenericPad::initialCycle() std::vector reportDesc = getReportDescriptor(); m_parser.Parse(reportDesc.data(), reportDesc.size()); #endif - if (m_cb) - m_cb->controllerConnected(); + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerConnected(); } void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { - if (length == 0 || tp != HIDReportType::Input || !m_cb) + std::lock_guard lk(m_callbackLock); + if (length == 0 || tp != HIDReportType::Input || !m_callback) return; std::function func = [this](const HIDMainItem& item, int32_t value) { - m_cb->valueUpdate(item, value); + m_callback->valueUpdate(item, value); return true; }; m_parser.ScanValues(func, data, length); diff --git a/lib/inputdev/HIDDeviceIOKit.cpp b/lib/inputdev/HIDDeviceIOKit.cpp index e904b05..8fb2a85 100644 --- a/lib/inputdev/HIDDeviceIOKit.cpp +++ b/lib/inputdev/HIDDeviceIOKit.cpp @@ -100,14 +100,15 @@ class HIDDeviceIOKit : public IHIDDevice IOObjectPointer devIter; IOObjectPointer devEntry = IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data()); - IORegistryEntryGetChildIterator(devEntry, kIOServicePlane, &devIter); IOObjectPointer interfaceEntry; - while (IOObjectPointer obj = IOIteratorNext(devIter)) + IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter); + while (IOObjectPointer obj = IOIteratorNext(devIter.get())) { - if (IOObjectConformsTo(obj, kIOUSBInterfaceClassName)) + if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName)) + { interfaceEntry = obj; - else - IOObjectRelease(obj); + break; + } } if (!interfaceEntry) { @@ -124,7 +125,7 @@ class HIDDeviceIOKit : public IHIDDevice IOCFPluginPointer iodev; SInt32 score; IOReturn err; - err = IOCreatePlugInInterfaceForService(interfaceEntry, + err = IOCreatePlugInInterfaceForService(interfaceEntry.get(), kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, diff --git a/lib/inputdev/HIDListenerIOKit.cpp b/lib/inputdev/HIDListenerIOKit.cpp index 7defca1..35e6ecb 100644 --- a/lib/inputdev/HIDListenerIOKit.cpp +++ b/lib/inputdev/HIDListenerIOKit.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "IOKitPointer.hpp" #include "CFPointer.hpp" @@ -67,10 +68,11 @@ class HIDListenerIOKit : public IHIDListener IONotificationPortRef m_llPort; IOObjectPointer m_llAddNotif, m_llRemoveNotif; IOObjectPointer m_hidAddNotif, m_hidRemoveNotif; + const char* m_usbClass; bool m_scanningEnabled; static void devicesConnectedUSBLL(HIDListenerIOKit* listener, - io_iterator_t iterator) + io_iterator_t iterator) { while (IOObjectPointer obj = IOIteratorNext(iterator)) { @@ -118,7 +120,7 @@ class HIDListenerIOKit : public IHIDListener listener->m_finder._insertToken(std::make_unique(DeviceType::USB, vid, pid, vstr, pstr, devPath)); - //printf("ADDED %08X %s\n", obj, devPath); + //printf("ADDED %08X %s\n", obj.get(), devPath); } } @@ -139,7 +141,7 @@ class HIDListenerIOKit : public IHIDListener if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) continue; listener->m_finder._removeToken(devPath); - //printf("REMOVED %08X %s\n", obj, devPath); + //printf("REMOVED %08X %s\n", obj.get(), devPath); } } @@ -244,6 +246,11 @@ public: HIDListenerIOKit(DeviceFinder& finder) : m_finder(finder) { + struct utsname kernInfo; + uname(&kernInfo); + int release = atoi(kernInfo.release); + m_usbClass = release >= 15 ? "IOUSBHostDevice" : kIOUSBDeviceClassName; + m_listenerRunLoop = CFRunLoopGetMain(); m_llPort = IONotificationPortCreate(kIOMasterPortDefault); CFRunLoopSourceRef rlSrc = IONotificationPortGetRunLoopSource(m_llPort); @@ -270,7 +277,7 @@ public: /* Register Low-Level USB Matcher */ { - CFMutableDictionaryRef matchDict = IOServiceMatching(kIOUSBDeviceClassName); + CFMutableDictionaryRef matchDict = IOServiceMatching(m_usbClass); CFRetain(matchDict); kern_return_t llRet = @@ -312,7 +319,7 @@ public: { IOObjectPointer iter; if (IOServiceGetMatchingServices(kIOMasterPortDefault, - IOServiceMatching(kIOUSBDeviceClassName), &iter) == kIOReturnSuccess) + IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess) { devicesConnectedUSBLL(this, iter.get()); } diff --git a/lib/inputdev/HIDListenerWinUSB.cpp b/lib/inputdev/HIDListenerWinUSB.cpp index eac152c..8da97a7 100644 --- a/lib/inputdev/HIDListenerWinUSB.cpp +++ b/lib/inputdev/HIDListenerWinUSB.cpp @@ -218,6 +218,7 @@ class HIDListenerWinUSB final : public IHIDListener if (tok.m_connectedDev) { XInputPad& pad = static_cast(*tok.m_connectedDev); + std::lock_guard lk(pad.m_callbackLock); if (pad.m_callback) pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad)); } diff --git a/lib/inputdev/NintendoPowerA.cpp b/lib/inputdev/NintendoPowerA.cpp index 7d278eb..b41adfe 100644 --- a/lib/inputdev/NintendoPowerA.cpp +++ b/lib/inputdev/NintendoPowerA.cpp @@ -3,7 +3,7 @@ namespace boo { NintendoPowerA::NintendoPowerA(DeviceToken* token) - : DeviceBase(token) + : TDeviceBase(token) { } @@ -14,6 +14,7 @@ NintendoPowerA::~NintendoPowerA() void NintendoPowerA::deviceDisconnected() { + std::lock_guard lk(m_callbackLock); if (m_callback) m_callback->controllerDisconnected(); } @@ -29,6 +30,7 @@ void NintendoPowerA::transferCycle() NintendoPowerAState state = *reinterpret_cast(&payload); + std::lock_guard lk(m_callbackLock); if (state != m_last && m_callback) m_callback->controllerUpdate(state); m_last = state;