diff --git a/include/inputdev/CDeviceBase.hpp b/include/inputdev/CDeviceBase.hpp index 20a4636..b2c068a 100644 --- a/include/inputdev/CDeviceBase.hpp +++ b/include/inputdev/CDeviceBase.hpp @@ -11,8 +11,8 @@ class CDeviceBase friend CDeviceToken; void _deviceDisconnected(); public: - inline CDeviceBase(CDeviceToken* token, IHIDDevice* hidDev) - : m_token(token), m_hidDev(hidDev) {} + CDeviceBase(CDeviceToken* token, IHIDDevice* hidDev); + virtual ~CDeviceBase(); void closeDevice(); virtual void deviceDisconnected()=0; }; diff --git a/include/inputdev/CDeviceFinder.hpp b/include/inputdev/CDeviceFinder.hpp index 7f6ef05..30da74f 100644 --- a/include/inputdev/CDeviceFinder.hpp +++ b/include/inputdev/CDeviceFinder.hpp @@ -55,8 +55,9 @@ private: if (preCheck != m_tokens.end()) { CDeviceToken& tok = preCheck->second; + CDeviceBase* dev = tok.m_connectedDev; tok._deviceClose(); - deviceDisconnected(tok); + deviceDisconnected(tok, dev); m_tokensLock.lock(); m_tokens.erase(preCheck); m_tokensLock.unlock(); @@ -127,7 +128,7 @@ public: } virtual void deviceConnected(CDeviceToken&) {} - virtual void deviceDisconnected(CDeviceToken&) {} + virtual void deviceDisconnected(CDeviceToken&, CDeviceBase*) {} }; diff --git a/include/inputdev/CDeviceToken.hpp b/include/inputdev/CDeviceToken.hpp index 1f4fb26..9109dbd 100644 --- a/include/inputdev/CDeviceToken.hpp +++ b/include/inputdev/CDeviceToken.hpp @@ -26,7 +26,6 @@ class CDeviceToken friend class CDeviceFinder; inline void _deviceClose() { - printf("CLOSE %p\n", this); if (m_connectedDev) m_connectedDev->_deviceDisconnected(); m_connectedDev = NULL; @@ -52,7 +51,6 @@ public: inline bool isDeviceOpen() const {return m_connectedDev;} inline CDeviceBase* openAndGetDevice() { - printf("OPEN %p\n", this); if (!m_connectedDev) m_connectedDev = BooDeviceNew(this); return m_connectedDev; diff --git a/include/inputdev/CDolphinSmashAdapter.hpp b/include/inputdev/CDolphinSmashAdapter.hpp index 6ea8ff3..50fb7e0 100644 --- a/include/inputdev/CDolphinSmashAdapter.hpp +++ b/include/inputdev/CDolphinSmashAdapter.hpp @@ -8,6 +8,7 @@ class CDolphinSmashAdapter final : public CDeviceBase void deviceDisconnected(); public: CDolphinSmashAdapter(CDeviceToken* token, IHIDDevice* hidDev); + ~CDolphinSmashAdapter(); }; #endif // CDOLPHINSMASHADAPTER_HPP diff --git a/include/inputdev/DeviceClasses.hpp b/include/inputdev/DeviceClasses.hpp index 5b5320c..42c3c4e 100644 --- a/include/inputdev/DeviceClasses.hpp +++ b/include/inputdev/DeviceClasses.hpp @@ -7,6 +7,9 @@ #include "CDualshockPad.hpp" #include "CGenericPad.hpp" +#define VID_NINTENDO 0x57e +#define PID_SMASH_ADAPTER 0x337 + enum EDeviceMask { DEV_NONE = 0, diff --git a/src/inputdev/CDeviceBase.cpp b/src/inputdev/CDeviceBase.cpp index aa3eff7..d748986 100644 --- a/src/inputdev/CDeviceBase.cpp +++ b/src/inputdev/CDeviceBase.cpp @@ -2,17 +2,30 @@ #include "inputdev/CDeviceToken.hpp" #include "IHIDDevice.hpp" +CDeviceBase::CDeviceBase(CDeviceToken* token, IHIDDevice* hidDev) +: m_token(token), m_hidDev(hidDev) +{ + hidDev->_setDeviceImp(this); +} + +CDeviceBase::~CDeviceBase() +{ + delete m_hidDev; +} void CDeviceBase::_deviceDisconnected() { deviceDisconnected(); m_token = NULL; - m_hidDev->_deviceDisconnected(); - m_hidDev = NULL; + if (m_hidDev) + { + m_hidDev->_deviceDisconnected(); + delete m_hidDev; + m_hidDev = NULL; + } } - void CDeviceBase::closeDevice() { if (m_token) diff --git a/src/inputdev/CDolphinSmashAdapter.cpp b/src/inputdev/CDolphinSmashAdapter.cpp index 8489379..0dbd6b1 100644 --- a/src/inputdev/CDolphinSmashAdapter.cpp +++ b/src/inputdev/CDolphinSmashAdapter.cpp @@ -4,10 +4,15 @@ CDolphinSmashAdapter::CDolphinSmashAdapter(CDeviceToken* token, IHIDDevice* hidDev) : CDeviceBase(token, hidDev) { - printf("I've been plugged!!\n"); + +} + +CDolphinSmashAdapter::~CDolphinSmashAdapter() +{ + } void CDolphinSmashAdapter::deviceDisconnected() { - printf("I've been unplugged!!\n"); + } diff --git a/src/inputdev/CHIDDeviceIOKit.cpp b/src/inputdev/CHIDDeviceIOKit.cpp index 990a298..81675a9 100644 --- a/src/inputdev/CHIDDeviceIOKit.cpp +++ b/src/inputdev/CHIDDeviceIOKit.cpp @@ -1,27 +1,92 @@ #include "IHIDDevice.hpp" #include "inputdev/CDeviceToken.hpp" +#include "inputdev/CDeviceBase.hpp" #include +#include + +#define MAX_REPORT_SIZE 65536 class CHIDDeviceIOKit final : public IHIDDevice { + CDeviceToken* m_token; IOHIDDeviceRef m_dev; + std::mutex m_initMutex; + std::condition_variable m_initCond; + std::thread* m_thread; + CFRunLoopRef m_runLoop; + CDeviceBase* m_devImp; + + static void _inputReport(CHIDDeviceIOKit* device, + IOReturn result, + void* sender, + IOHIDReportType type, + uint32_t reportID, + uint8_t* report, + CFIndex reportLength) + { + + } + static void _disconnect(CHIDDeviceIOKit* device, + IOReturn result, + IOHIDDeviceRef sender) + { + device->_deviceDisconnected(); + } + static void _threadProc(CHIDDeviceIOKit* device) + { + char thrName[128]; + snprintf(thrName, 128, "%s Device Thread", device->m_token->getProductName().c_str()); + pthread_setname_np(thrName); + __block std::unique_lock lk(device->m_initMutex); + device->m_runLoop = CFRunLoopGetCurrent(); + CFRunLoopAddObserver(device->m_runLoop, + CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopEntry, false, 0, + ^(CFRunLoopObserverRef, CFRunLoopActivity) { + lk.unlock(); + device->m_initCond.notify_one(); + }), kCFRunLoopCommonModes); + + uint8_t* inputBuf = new uint8_t[MAX_REPORT_SIZE]; + IOHIDDeviceRegisterInputReportCallback(device->m_dev, inputBuf, MAX_REPORT_SIZE, + (IOHIDReportCallback)_inputReport, device); + IOHIDDeviceRegisterRemovalCallback(device->m_dev, (IOHIDCallback)_disconnect, device); + IOHIDDeviceScheduleWithRunLoop(device->m_dev, device->m_runLoop, kCFRunLoopDefaultMode); + IOHIDDeviceOpen(device->m_dev, kIOHIDOptionsTypeNone); + CFRunLoopRun(); + if (device->m_runLoop) + IOHIDDeviceClose(device->m_dev, kIOHIDOptionsTypeNone); + } void _deviceDisconnected() { - IOHIDDeviceClose(m_dev, kIOHIDOptionsTypeNone); + CFRunLoopRef rl = m_runLoop; + m_runLoop = NULL; + if (rl) + CFRunLoopStop(rl); + } + + void _setDeviceImp(CDeviceBase* dev) + { + m_devImp = dev; } public: CHIDDeviceIOKit(CDeviceToken* token) - : m_dev(token->getDeviceHandle()) + : m_token(token), + m_dev(token->getDeviceHandle()) { - IOHIDDeviceOpen(m_dev, kIOHIDOptionsTypeNone); + std::unique_lock lk(m_initMutex); + m_thread = new std::thread(_threadProc, this); + m_initCond.wait(lk); } ~CHIDDeviceIOKit() { - IOHIDDeviceClose(m_dev, kIOHIDOptionsTypeNone); + if (m_runLoop) + CFRunLoopStop(m_runLoop); + m_thread->detach(); + delete m_thread; } diff --git a/src/inputdev/CHIDListenerIOKit.cpp b/src/inputdev/CHIDListenerIOKit.cpp index 6aa964d..09a9325 100644 --- a/src/inputdev/CHIDListenerIOKit.cpp +++ b/src/inputdev/CHIDListenerIOKit.cpp @@ -7,6 +7,7 @@ class CHIDListenerIOKit final : public IHIDListener { CDeviceFinder& m_finder; + CFRunLoopRef m_listenerRunLoop; IOHIDManagerRef m_hidManager; bool m_scanningEnabled; @@ -31,10 +32,18 @@ class CHIDListenerIOKit final : public IHIDListener } static void deviceDisconnected(CHIDListenerIOKit* listener, - IOReturn, - void*, + IOReturn ret, + void* sender, IOHIDDeviceRef device) { + if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) + { + CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode, ^{ + deviceDisconnected(listener, ret, sender, device); + }); + CFRunLoopWakeUp(listener->m_listenerRunLoop); + return; + } listener->m_finder._removeToken(device); } @@ -63,7 +72,8 @@ public: IOHIDManagerSetDeviceMatching(m_hidManager, NULL); IOHIDManagerRegisterDeviceMatchingCallback(m_hidManager, (IOHIDDeviceCallback)deviceConnected, this); IOHIDManagerRegisterDeviceRemovalCallback(m_hidManager, (IOHIDDeviceCallback)deviceDisconnected, this); - IOHIDManagerScheduleWithRunLoop(m_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + m_listenerRunLoop = CFRunLoopGetCurrent(); + IOHIDManagerScheduleWithRunLoop(m_hidManager, m_listenerRunLoop, kCFRunLoopDefaultMode); IOReturn ret = IOHIDManagerOpen(m_hidManager, kIOHIDManagerOptionNone); if (ret != kIOReturnSuccess) throw std::runtime_error("error establishing IOHIDManager"); @@ -77,7 +87,7 @@ public: ~CHIDListenerIOKit() { - IOHIDManagerUnscheduleFromRunLoop(m_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDManagerUnscheduleFromRunLoop(m_hidManager, m_listenerRunLoop, kCFRunLoopDefaultMode); IOHIDManagerClose(m_hidManager, kIOHIDManagerOptionNone); CFRelease(m_hidManager); } diff --git a/src/inputdev/DeviceClasses.cpp b/src/inputdev/DeviceClasses.cpp index be5e530..8c6c0e3 100644 --- a/src/inputdev/DeviceClasses.cpp +++ b/src/inputdev/DeviceClasses.cpp @@ -1,10 +1,11 @@ #include "inputdev/DeviceClasses.hpp" #include "inputdev/CDeviceToken.hpp" +#include "IHIDDevice.hpp" bool BooDeviceMatchToken(const CDeviceToken& token, EDeviceMask mask) { if (mask & DEV_DOL_SMASH_ADAPTER && - token.getVendorId() == 0x57e && token.getProductId() == 0x337) + token.getVendorId() == VID_NINTENDO && token.getProductId() == PID_SMASH_ADAPTER) return true; return false; } @@ -13,9 +14,13 @@ IHIDDevice* IHIDDeviceNew(CDeviceToken* token); CDeviceBase* BooDeviceNew(CDeviceToken* token) { IHIDDevice* newDev = IHIDDeviceNew(token); + if (!newDev) + return NULL; - if (token->getVendorId() == 0x57e && token->getProductId() == 0x337) + if (token->getVendorId() == VID_NINTENDO && token->getProductId() == PID_SMASH_ADAPTER) return new CDolphinSmashAdapter(token, newDev); + else + delete newDev; return NULL; } diff --git a/src/inputdev/IHIDDevice.hpp b/src/inputdev/IHIDDevice.hpp index 58174f7..7f3da47 100644 --- a/src/inputdev/IHIDDevice.hpp +++ b/src/inputdev/IHIDDevice.hpp @@ -7,7 +7,10 @@ class CDeviceBase; class IHIDDevice { friend CDeviceBase; + virtual void _setDeviceImp(CDeviceBase* dev)=0; virtual void _deviceDisconnected()=0; +public: + inline virtual ~IHIDDevice() {}; }; #endif // IHIDDEVICE_HPP diff --git a/test/main.cpp b/test/main.cpp index c0e221d..1ee6aa1 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -12,14 +12,15 @@ public: {} void deviceConnected(CDeviceToken& tok) { - printf("CONNECTED %s %s\n", tok.getVendorName().c_str(), tok.getProductName().c_str()); smashAdapter = dynamic_cast(tok.openAndGetDevice()); } - void deviceDisconnected(CDeviceToken& tok) + void deviceDisconnected(CDeviceToken&, CDeviceBase* device) { - printf("DISCONNECTED %s %s\n", tok.getVendorName().c_str(), tok.getProductName().c_str()); - delete smashAdapter; - smashAdapter = NULL; + if (smashAdapter == device) + { + delete smashAdapter; + smashAdapter = NULL; + } } };