macOS IOKit interface fixes; callback-change mutex for controllers

This commit is contained in:
Jack Andersen 2017-12-15 13:35:54 -10:00
parent cb99c05284
commit e0aa15610b
15 changed files with 87 additions and 52 deletions

View File

@ -6,6 +6,7 @@
#include <stdio.h>
#include <memory>
#include <vector>
#include <mutex>
#include "boo/System.hpp"
#if _WIN32
@ -36,7 +37,7 @@ class DeviceBase : public std::enable_shared_from_this<DeviceBase>
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 CB>
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<std::mutex> lk(m_callbackLock);
m_callback = cb;
}
};
}
#endif // CDEVICEBASE

View File

@ -112,7 +112,7 @@ public:
}
}
}
~DeviceFinder()
virtual ~DeviceFinder()
{
if (m_listener)
m_listener->stopScanning();

View File

@ -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>
{
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<IDolphinSmashAdapterCallback>::setCallback(cb);
m_knownControllers = 0;
}
void startRumble(unsigned idx)
{if (idx >= 4) return; m_rumbleRequest |= 1<<idx;}
void stopRumble(unsigned idx, bool hard=false)

View File

@ -122,9 +122,8 @@ struct IDualshockPadCallback
virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {}
};
class DualshockPad final : public DeviceBase
class DualshockPad final : public TDeviceBase<IDualshockPadCallback>
{
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;

View File

@ -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<IGenericPadCallback>
{
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);

View File

@ -37,9 +37,8 @@ struct INintendoPowerACallback
virtual void controllerUpdate(const NintendoPowerAState& state) {}
};
class NintendoPowerA final : public DeviceBase
class NintendoPowerA final : public TDeviceBase<INintendoPowerACallback>
{
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; }
};
}

View File

@ -33,17 +33,16 @@ struct IXInputPadCallback
virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {}
};
class XInputPad final : public DeviceBase
class XInputPad final : public TDeviceBase<IXInputPadCallback>
{
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<IXInputPadCallback>(token) {}
void deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}

View File

@ -11,10 +11,6 @@ DeviceBase::DeviceBase(DeviceToken* token)
{
}
DeviceBase::~DeviceBase()
{
}
void DeviceBase::_deviceDisconnected()
{
deviceDisconnected();

View File

@ -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<IDolphinSmashAdapterCallback>(token) {}
DolphinSmashAdapter::~DolphinSmashAdapter() {}
@ -61,6 +61,7 @@ void DolphinSmashAdapter::transferCycle()
// printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
std::lock_guard<std::mutex> 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<uint8_t&>(state.m_leftStick[0]);
m_leftStickCal[1] = reinterpret_cast<uint8_t&>(state.m_leftStick[1]);
m_rightStickCal[0] = reinterpret_cast<uint8_t&>(state.m_rightStick[0]);
m_rightStickCal[1] = reinterpret_cast<uint8_t&>(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<uint8_t&>(state.m_leftStick[0]) - m_leftStickCal[0]);
state.m_leftStick[1] = int8_t(reinterpret_cast<uint8_t&>(state.m_leftStick[1]) - m_leftStickCal[1]);
state.m_rightStick[0] = int8_t(reinterpret_cast<uint8_t&>(state.m_rightStick[0]) - m_rightStickCal[0]);
state.m_rightStick[1] = int8_t(reinterpret_cast<uint8_t&>(state.m_rightStick[1]) - m_rightStickCal[1]);
m_callback->controllerUpdate(i, type, state);
}
rumbleMask |= rumble ? 1 << i : 0;
}
@ -115,13 +126,13 @@ 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);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected(i);
}
}

View File

@ -29,8 +29,7 @@ static const uint8_t defaultReport[49] = {
};
DualshockPad::DualshockPad(DeviceToken* token)
: DeviceBase(token),
m_callback(nullptr),
: TDeviceBase<IDualshockPadCallback>(token),
m_rumbleRequest(EDualshockMotor::None),
m_rumbleState(EDualshockMotor::None)
{
@ -44,6 +43,7 @@ DualshockPad::~DualshockPad()
void DualshockPad::deviceDisconnected()
{
std::lock_guard<std::mutex> 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);
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerUpdate(*this, state);
}
if (m_rumbleRequest != m_rumbleState)
{

View File

@ -5,7 +5,7 @@ namespace boo
{
GenericPad::GenericPad(DeviceToken* token)
: DeviceBase(token)
: TDeviceBase<IGenericPadCallback>(token)
{
}
@ -14,8 +14,9 @@ GenericPad::~GenericPad() {}
void GenericPad::deviceDisconnected()
{
if (m_cb)
m_cb->controllerDisconnected();
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void GenericPad::initialCycle()
@ -29,18 +30,20 @@ void GenericPad::initialCycle()
std::vector<uint8_t> reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc.data(), reportDesc.size());
#endif
if (m_cb)
m_cb->controllerConnected();
std::lock_guard<std::mutex> 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<std::mutex> lk(m_callbackLock);
if (length == 0 || tp != HIDReportType::Input || !m_callback)
return;
std::function<bool(const HIDMainItem&, int32_t)> 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);

View File

@ -100,14 +100,15 @@ class HIDDeviceIOKit : public IHIDDevice
IOObjectPointer<io_iterator_t> devIter;
IOObjectPointer<io_registry_entry_t> devEntry = IORegistryEntryFromPath(kIOMasterPortDefault,
device->m_devPath.data());
IORegistryEntryGetChildIterator(devEntry, kIOServicePlane, &devIter);
IOObjectPointer<io_object_t> interfaceEntry;
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter))
IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter);
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get()))
{
if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName))
{
if (IOObjectConformsTo(obj, 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,

View File

@ -7,6 +7,7 @@
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <sys/utsname.h>
#include "IOKitPointer.hpp"
#include "CFPointer.hpp"
@ -67,6 +68,7 @@ class HIDListenerIOKit : public IHIDListener
IONotificationPortRef m_llPort;
IOObjectPointer<io_iterator_t> m_llAddNotif, m_llRemoveNotif;
IOObjectPointer<io_iterator_t> m_hidAddNotif, m_hidRemoveNotif;
const char* m_usbClass;
bool m_scanningEnabled;
static void devicesConnectedUSBLL(HIDListenerIOKit* listener,
@ -118,7 +120,7 @@ class HIDListenerIOKit : public IHIDListener
listener->m_finder._insertToken(std::make_unique<DeviceToken>(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<io_iterator_t> iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching(kIOUSBDeviceClassName), &iter) == kIOReturnSuccess)
IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess)
{
devicesConnectedUSBLL(this, iter.get());
}

View File

@ -218,6 +218,7 @@ class HIDListenerWinUSB final : public IHIDListener
if (tok.m_connectedDev)
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
std::lock_guard<std::mutex> lk(pad.m_callbackLock);
if (pad.m_callback)
pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad));
}

View File

@ -3,7 +3,7 @@
namespace boo
{
NintendoPowerA::NintendoPowerA(DeviceToken* token)
: DeviceBase(token)
: TDeviceBase<INintendoPowerACallback>(token)
{
}
@ -14,6 +14,7 @@ NintendoPowerA::~NintendoPowerA()
void NintendoPowerA::deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
@ -29,6 +30,7 @@ void NintendoPowerA::transferCycle()
NintendoPowerAState state = *reinterpret_cast<NintendoPowerAState*>(&payload);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (state != m_last && m_callback)
m_callback->controllerUpdate(state);
m_last = state;