mirror of https://github.com/AxioDL/boo.git
better generic HID differentiation; smash udev working
This commit is contained in:
parent
4b8651b844
commit
1125e20b6e
|
@ -6,7 +6,7 @@ namespace boo
|
||||||
|
|
||||||
const SDeviceSignature BOO_DEVICE_SIGS[] =
|
const SDeviceSignature BOO_DEVICE_SIGS[] =
|
||||||
{
|
{
|
||||||
DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337, true),
|
DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337),
|
||||||
DEVICE_SIG_SENTINEL()
|
DEVICE_SIG_SENTINEL()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,14 @@ public:
|
||||||
virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);}
|
virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);}
|
||||||
|
|
||||||
/* Low-Level API */
|
/* Low-Level API */
|
||||||
bool sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length);
|
bool sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length);
|
||||||
size_t receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length);
|
size_t receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length);
|
||||||
virtual void initialCycle() {}
|
virtual void initialCycle() {}
|
||||||
virtual void transferCycle() {}
|
virtual void transferCycle() {}
|
||||||
virtual void finalCycle() {}
|
virtual void finalCycle() {}
|
||||||
|
|
||||||
/* High-Level API */
|
/* High-Level API */
|
||||||
bool sendReport(const uint8_t* data, size_t length);
|
bool sendHIDReport(const uint8_t* data, size_t length);
|
||||||
virtual size_t receiveReport(uint8_t* data, size_t length) {return 0;}
|
virtual size_t receiveReport(uint8_t* data, size_t length) {return 0;}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,7 @@ private:
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
inline void _insertToken(CDeviceToken&& token)
|
inline bool _insertToken(CDeviceToken&& token)
|
||||||
{
|
{
|
||||||
if (SDeviceSignature::DeviceMatchToken(token, m_types)) {
|
if (SDeviceSignature::DeviceMatchToken(token, m_types)) {
|
||||||
m_tokensLock.lock();
|
m_tokensLock.lock();
|
||||||
|
@ -52,7 +52,9 @@ private:
|
||||||
m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token)));
|
m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token)));
|
||||||
m_tokensLock.unlock();
|
m_tokensLock.unlock();
|
||||||
deviceConnected(inseredTok.first->second);
|
deviceConnected(inseredTok.first->second);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
inline void _removeToken(const std::string& path)
|
inline void _removeToken(const std::string& path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,17 @@ namespace boo
|
||||||
|
|
||||||
class CDeviceToken
|
class CDeviceToken
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
enum TDeviceType
|
||||||
|
{
|
||||||
|
DEVTYPE_NONE = 0,
|
||||||
|
DEVTYPE_USB = 1,
|
||||||
|
DEVTYPE_BLUETOOTH = 2,
|
||||||
|
DEVTYPE_GENERICHID = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
TDeviceType m_devType;
|
||||||
unsigned m_vendorId;
|
unsigned m_vendorId;
|
||||||
unsigned m_productId;
|
unsigned m_productId;
|
||||||
std::string m_vendorName;
|
std::string m_vendorName;
|
||||||
|
@ -28,10 +39,11 @@ class CDeviceToken
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CDeviceToken(const CDeviceToken&) = delete;
|
CDeviceToken(const CDeviceToken&) = delete;
|
||||||
CDeviceToken(CDeviceToken&&) = default;
|
CDeviceToken(CDeviceToken&&) = default;
|
||||||
inline CDeviceToken(unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path)
|
inline CDeviceToken(enum TDeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path)
|
||||||
: m_vendorId(vid), m_productId(pid), m_devPath(path), m_connectedDev(NULL)
|
: m_devType(devType), m_vendorId(vid), m_productId(pid), m_devPath(path), m_connectedDev(NULL)
|
||||||
{
|
{
|
||||||
if (vname)
|
if (vname)
|
||||||
m_vendorName = vname;
|
m_vendorName = vname;
|
||||||
|
@ -39,6 +51,7 @@ public:
|
||||||
m_productName = pname;
|
m_productName = pname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline TDeviceType getDeviceType() const {return m_devType;}
|
||||||
inline unsigned getVendorId() const {return m_vendorId;}
|
inline unsigned getVendorId() const {return m_vendorId;}
|
||||||
inline unsigned getProductId() const {return m_productId;}
|
inline unsigned getProductId() const {return m_productId;}
|
||||||
inline const std::string& getVendorName() const {return m_vendorName;}
|
inline const std::string& getVendorName() const {return m_vendorName;}
|
||||||
|
|
|
@ -52,7 +52,6 @@ class CDolphinSmashAdapter final : public CDeviceBase
|
||||||
uint8_t m_knownControllers;
|
uint8_t m_knownControllers;
|
||||||
uint8_t m_rumbleRequest;
|
uint8_t m_rumbleRequest;
|
||||||
uint8_t m_rumbleState;
|
uint8_t m_rumbleState;
|
||||||
bool m_didHandshake;
|
|
||||||
void deviceDisconnected();
|
void deviceDisconnected();
|
||||||
void initialCycle();
|
void initialCycle();
|
||||||
void transferCycle();
|
void transferCycle();
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
#ifndef CGENERICPAD_HPP
|
#ifndef CGENERICPAD_HPP
|
||||||
#define CGENERICPAD_HPP
|
#define CGENERICPAD_HPP
|
||||||
|
|
||||||
|
#include "CDeviceBase.hpp"
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class CGenericPad final : public CDeviceBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CGenericPad(CDeviceToken* token);
|
||||||
|
~CGenericPad();
|
||||||
|
|
||||||
|
void deviceDisconnected();
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CGENERICPAD_HPP
|
#endif // CGENERICPAD_HPP
|
||||||
|
|
|
@ -16,17 +16,16 @@ struct SDeviceSignature
|
||||||
typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda;
|
typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda;
|
||||||
const char* m_name;
|
const char* m_name;
|
||||||
unsigned m_vid, m_pid;
|
unsigned m_vid, m_pid;
|
||||||
bool m_lowLevel;
|
|
||||||
TFactoryLambda m_factory;
|
TFactoryLambda m_factory;
|
||||||
SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */
|
SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */
|
||||||
SDeviceSignature(const char* name, unsigned vid, unsigned pid, bool lowLevel, TFactoryLambda&& factory)
|
SDeviceSignature(const char* name, unsigned vid, unsigned pid, TFactoryLambda&& factory)
|
||||||
: m_name(name), m_vid(vid), m_pid(pid), m_lowLevel(lowLevel), m_factory(factory) {}
|
: m_name(name), m_vid(vid), m_pid(pid), m_factory(factory) {}
|
||||||
static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet);
|
static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet);
|
||||||
static CDeviceBase* DeviceNew(CDeviceToken& token);
|
static CDeviceBase* DeviceNew(CDeviceToken& token);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEVICE_SIG(name, vid, pid, lowLevel) \
|
#define DEVICE_SIG(name, vid, pid) \
|
||||||
SDeviceSignature(#name, vid, pid, lowLevel, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
|
SDeviceSignature(#name, vid, pid, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
|
||||||
#define DEVICE_SIG_SENTINEL() SDeviceSignature()
|
#define DEVICE_SIG_SENTINEL() SDeviceSignature()
|
||||||
|
|
||||||
extern const SDeviceSignature BOO_DEVICE_SIGS[];
|
extern const SDeviceSignature BOO_DEVICE_SIGS[];
|
||||||
|
|
|
@ -33,24 +33,24 @@ void CDeviceBase::closeDevice()
|
||||||
m_token->_deviceClose();
|
m_token->_deviceClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDeviceBase::sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
|
bool CDeviceBase::sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_hidDev)
|
if (m_hidDev)
|
||||||
return m_hidDev->_sendInterruptTransfer(pipe, data, length);
|
return m_hidDev->_sendUSBInterruptTransfer(pipe, data, length);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CDeviceBase::receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
|
size_t CDeviceBase::receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_hidDev)
|
if (m_hidDev)
|
||||||
return m_hidDev->_receiveInterruptTransfer(pipe, data, length);
|
return m_hidDev->_receiveUSBInterruptTransfer(pipe, data, length);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDeviceBase::sendReport(const uint8_t* data, size_t length)
|
bool CDeviceBase::sendHIDReport(const uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_hidDev)
|
if (m_hidDev)
|
||||||
return m_hidDev->_sendReport(data, length);
|
return m_hidDev->_sendHIDReport(data, length);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@ CDolphinSmashAdapter::CDolphinSmashAdapter(CDeviceToken* token)
|
||||||
m_callback(NULL),
|
m_callback(NULL),
|
||||||
m_knownControllers(0),
|
m_knownControllers(0),
|
||||||
m_rumbleRequest(0),
|
m_rumbleRequest(0),
|
||||||
m_rumbleState(0),
|
m_rumbleState(0)
|
||||||
m_didHandshake(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +22,6 @@ CDolphinSmashAdapter::~CDolphinSmashAdapter()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t HANDSHAKE_PAYLOAD[] = {0x13};
|
|
||||||
|
|
||||||
static inline EDolphinControllerType parseType(unsigned char status)
|
static inline EDolphinControllerType parseType(unsigned char status)
|
||||||
{
|
{
|
||||||
unsigned char type = status & (DOL_TYPE_NORMAL | DOL_TYPE_WAVEBIRD);
|
unsigned char type = status & (DOL_TYPE_NORMAL | DOL_TYPE_WAVEBIRD);
|
||||||
|
@ -61,77 +58,65 @@ parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
|
||||||
|
|
||||||
void CDolphinSmashAdapter::transferCycle()
|
void CDolphinSmashAdapter::transferCycle()
|
||||||
{
|
{
|
||||||
if (!m_didHandshake)
|
uint8_t payload[37];
|
||||||
|
size_t recvSz = receiveUSBInterruptTransfer(0, payload, sizeof(payload));
|
||||||
|
if (recvSz != 37 || payload[0] != 0x21)
|
||||||
|
return;
|
||||||
|
//printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
|
||||||
|
|
||||||
|
if (!m_callback)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Parse controller states */
|
||||||
|
uint8_t* controller = &payload[1];
|
||||||
|
uint8_t rumbleMask = 0;
|
||||||
|
for (int i=0 ; i<4 ; i++, controller += 9)
|
||||||
{
|
{
|
||||||
if (!sendInterruptTransfer(0, HANDSHAKE_PAYLOAD, sizeof(HANDSHAKE_PAYLOAD)))
|
SDolphinControllerState state;
|
||||||
return;
|
bool rumble = false;
|
||||||
//printf("SENT HANDSHAKE %d\n", res);
|
EDolphinControllerType type = parseState(&state, controller, rumble);
|
||||||
m_didHandshake = true;
|
if (type && !(m_knownControllers & 1<<i))
|
||||||
|
{
|
||||||
|
m_knownControllers |= 1<<i;
|
||||||
|
m_callback->controllerConnected(i, type);
|
||||||
|
}
|
||||||
|
else if (!type && (m_knownControllers & 1<<i))
|
||||||
|
{
|
||||||
|
m_knownControllers &= ~(1<<i);
|
||||||
|
m_callback->controllerDisconnected(i, type);
|
||||||
|
}
|
||||||
|
if (m_knownControllers & 1<<i)
|
||||||
|
m_callback->controllerUpdate(i, type, state);
|
||||||
|
rumbleMask |= rumble ? 1<<i : 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/* Send rumble message (if needed) */
|
||||||
|
uint8_t rumbleReq = m_rumbleRequest & rumbleMask;
|
||||||
|
if (rumbleReq != m_rumbleState)
|
||||||
{
|
{
|
||||||
uint8_t payload[37];
|
uint8_t rumbleMessage[5] = {0x11};
|
||||||
size_t recvSz = receiveInterruptTransfer(0, payload, sizeof(payload));
|
for (int i=0 ; i<4 ; ++i)
|
||||||
if (recvSz != 37 || payload[0] != 0x21)
|
|
||||||
return;
|
|
||||||
//printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
|
|
||||||
|
|
||||||
if (!m_callback)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Parse controller states */
|
|
||||||
uint8_t* controller = &payload[1];
|
|
||||||
uint8_t rumbleMask = 0;
|
|
||||||
for (int i=0 ; i<4 ; i++, controller += 9)
|
|
||||||
{
|
{
|
||||||
SDolphinControllerState state;
|
if (rumbleReq & 1<<i)
|
||||||
bool rumble = false;
|
rumbleMessage[i+1] = 1;
|
||||||
EDolphinControllerType type = parseState(&state, controller, rumble);
|
else
|
||||||
if (type && !(m_knownControllers & 1<<i))
|
rumbleMessage[i+1] = 0;
|
||||||
{
|
|
||||||
m_knownControllers |= 1<<i;
|
|
||||||
m_callback->controllerConnected(i, type);
|
|
||||||
}
|
|
||||||
else if (!type && (m_knownControllers & 1<<i))
|
|
||||||
{
|
|
||||||
m_knownControllers &= ~(1<<i);
|
|
||||||
m_callback->controllerDisconnected(i, type);
|
|
||||||
}
|
|
||||||
if (m_knownControllers & 1<<i)
|
|
||||||
m_callback->controllerUpdate(i, type, state);
|
|
||||||
rumbleMask |= rumble ? 1<<i : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send rumble message (if needed) */
|
|
||||||
uint8_t rumbleReq = m_rumbleRequest & rumbleMask;
|
|
||||||
if (rumbleReq != m_rumbleState)
|
|
||||||
{
|
|
||||||
uint8_t rumbleMessage[5] = {0x11};
|
|
||||||
for (int i=0 ; i<4 ; ++i)
|
|
||||||
{
|
|
||||||
if (rumbleReq & 1<<i)
|
|
||||||
rumbleMessage[i+1] = 1;
|
|
||||||
else
|
|
||||||
rumbleMessage[i+1] = 0;
|
|
||||||
}
|
|
||||||
sendInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
|
||||||
m_rumbleState = rumbleReq;
|
|
||||||
}
|
}
|
||||||
|
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
||||||
|
m_rumbleState = rumbleReq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDolphinSmashAdapter::initialCycle()
|
void CDolphinSmashAdapter::initialCycle()
|
||||||
{
|
{
|
||||||
|
uint8_t handshakePayload[] = {0x13};
|
||||||
|
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDolphinSmashAdapter::finalCycle()
|
void CDolphinSmashAdapter::finalCycle()
|
||||||
{
|
{
|
||||||
if (m_didHandshake)
|
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
||||||
{
|
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
||||||
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
|
||||||
sendInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDolphinSmashAdapter::deviceDisconnected()
|
void CDolphinSmashAdapter::deviceDisconnected()
|
||||||
|
|
|
@ -1 +1,23 @@
|
||||||
#include "inputdev/CGenericPad.hpp"
|
#include "inputdev/CGenericPad.hpp"
|
||||||
|
#include "inputdev/CDeviceToken.hpp"
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
CGenericPad::CGenericPad(CDeviceToken* token)
|
||||||
|
: CDeviceBase(token)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CGenericPad::~CGenericPad()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGenericPad::deviceDisconnected()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
||||||
std::thread* m_thread;
|
std::thread* m_thread;
|
||||||
CFRunLoopRef m_runLoop = NULL;
|
CFRunLoopRef m_runLoop = NULL;
|
||||||
|
|
||||||
bool _sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
|
bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_usbIntf)
|
if (m_usbIntf)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
|
size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_usbIntf)
|
if (m_usbIntf)
|
||||||
{
|
{
|
||||||
|
@ -215,7 +215,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
||||||
m_runningTransferLoop = false;
|
m_runningTransferLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _sendReport(const uint8_t* data, size_t length)
|
bool _sendHIDReport(const uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_runLoop)
|
if (m_runLoop)
|
||||||
{
|
{
|
||||||
|
@ -226,7 +226,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CHIDDeviceIOKit(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel)
|
CHIDDeviceIOKit(CDeviceToken& token, CDeviceBase& devImp)
|
||||||
: m_token(token),
|
: m_token(token),
|
||||||
m_devImp(devImp),
|
m_devImp(devImp),
|
||||||
m_devPath(token.getDevicePath())
|
m_devPath(token.getDevicePath())
|
||||||
|
@ -252,9 +252,9 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel)
|
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp)
|
||||||
{
|
{
|
||||||
return new CHIDDeviceIOKit(token, devImp, lowLevel);
|
return new CHIDDeviceIOKit(token, devImp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ class CHIDDeviceUdev final : public IHIDDevice
|
||||||
std::condition_variable m_initCond;
|
std::condition_variable m_initCond;
|
||||||
std::thread* m_thread;
|
std::thread* m_thread;
|
||||||
|
|
||||||
bool _sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
|
bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_devFd)
|
if (m_devFd)
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,7 @@ class CHIDDeviceUdev final : public IHIDDevice
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
|
size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
if (m_devFd)
|
if (m_devFd)
|
||||||
{
|
{
|
||||||
|
@ -75,15 +75,14 @@ class CHIDDeviceUdev final : public IHIDDevice
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _threadProcLL(CHIDDeviceUdev* device)
|
static void _threadProcUSBLL(CHIDDeviceUdev* device)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
||||||
udev_device* hidDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
|
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
|
||||||
|
|
||||||
/* Get the HID element's parent (USB interrupt transfer-interface) */
|
/* Get the HID element's parent (USB interrupt transfer-interface) */
|
||||||
udev_device* usbDev = udev_device_get_parent_with_subsystem_devtype(hidDev, "usb", "usb_device");
|
const char* dp = udev_device_get_devnode(udevDev);
|
||||||
const char* dp = udev_device_get_devnode(usbDev);
|
|
||||||
device->m_devFd = open(dp, O_RDWR);
|
device->m_devFd = open(dp, O_RDWR);
|
||||||
if (device->m_devFd < 0)
|
if (device->m_devFd < 0)
|
||||||
{
|
{
|
||||||
|
@ -93,7 +92,7 @@ class CHIDDeviceUdev final : public IHIDDevice
|
||||||
device->m_devImp.deviceError(errStr);
|
device->m_devImp.deviceError(errStr);
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
device->m_initCond.notify_one();
|
device->m_initCond.notify_one();
|
||||||
udev_device_unref(hidDev);
|
udev_device_unref(udevDev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
usb_device_descriptor devDesc = {0};
|
usb_device_descriptor devDesc = {0};
|
||||||
|
@ -147,13 +146,46 @@ class CHIDDeviceUdev final : public IHIDDevice
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
close(device->m_devFd);
|
close(device->m_devFd);
|
||||||
device->m_devFd = 0;
|
device->m_devFd = 0;
|
||||||
udev_device_unref(hidDev);
|
udev_device_unref(udevDev);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _threadProcHL(CHIDDeviceUdev* device)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
static void _threadProcBTLL(CHIDDeviceUdev* device)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
||||||
|
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
|
||||||
|
|
||||||
|
/* Return control to main thread */
|
||||||
|
device->m_runningTransferLoop = true;
|
||||||
|
lk.unlock();
|
||||||
|
device->m_initCond.notify_one();
|
||||||
|
|
||||||
|
/* Start transfer loop */
|
||||||
|
device->m_devImp.initialCycle();
|
||||||
|
while (device->m_runningTransferLoop)
|
||||||
|
device->m_devImp.transferCycle();
|
||||||
|
device->m_devImp.finalCycle();
|
||||||
|
|
||||||
|
udev_device_unref(udevDev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _threadProcHID(CHIDDeviceUdev* device)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
||||||
|
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
|
||||||
|
|
||||||
|
/* Return control to main thread */
|
||||||
|
device->m_runningTransferLoop = true;
|
||||||
|
lk.unlock();
|
||||||
|
device->m_initCond.notify_one();
|
||||||
|
|
||||||
|
/* Start transfer loop */
|
||||||
|
device->m_devImp.initialCycle();
|
||||||
|
while (device->m_runningTransferLoop)
|
||||||
|
device->m_devImp.transferCycle();
|
||||||
|
device->m_devImp.finalCycle();
|
||||||
|
|
||||||
|
udev_device_unref(udevDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deviceDisconnected()
|
void _deviceDisconnected()
|
||||||
|
@ -161,24 +193,29 @@ class CHIDDeviceUdev final : public IHIDDevice
|
||||||
m_runningTransferLoop = false;
|
m_runningTransferLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _sendReport(const uint8_t* data, size_t length)
|
bool _sendHIDReport(const uint8_t* data, size_t length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CHIDDeviceUdev(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel)
|
CHIDDeviceUdev(CDeviceToken& token, CDeviceBase& devImp)
|
||||||
: m_token(token),
|
: m_token(token),
|
||||||
m_devImp(devImp),
|
m_devImp(devImp),
|
||||||
m_devPath(token.getDevicePath())
|
m_devPath(token.getDevicePath())
|
||||||
{
|
{
|
||||||
devImp.m_hidDev = this;
|
devImp.m_hidDev = this;
|
||||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||||
if (lowLevel)
|
CDeviceToken::TDeviceType dType = token.getDeviceType();
|
||||||
m_thread = new std::thread(_threadProcLL, this);
|
if (dType == CDeviceToken::DEVTYPE_USB)
|
||||||
|
m_thread = new std::thread(_threadProcUSBLL, this);
|
||||||
|
else if (dType == CDeviceToken::DEVTYPE_BLUETOOTH)
|
||||||
|
m_thread = new std::thread(_threadProcBTLL, this);
|
||||||
|
else if (dType == CDeviceToken::DEVTYPE_GENERICHID)
|
||||||
|
m_thread = new std::thread(_threadProcHID, this);
|
||||||
else
|
else
|
||||||
m_thread = new std::thread(_threadProcHL, this);
|
throw std::runtime_error("invalid token supplied to device constructor");
|
||||||
m_initCond.wait(lk);
|
m_initCond.wait(lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,9 +229,9 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel)
|
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp)
|
||||||
{
|
{
|
||||||
return new CHIDDeviceUdev(token, devImp, lowLevel);
|
return new CHIDDeviceUdev(token, devImp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,19 +30,33 @@ class CHIDListenerUdev final : public IHIDListener
|
||||||
if (!listener->m_scanningEnabled)
|
if (!listener->m_scanningEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Filter to USB/BT */
|
||||||
|
const char* dt = udev_device_get_devtype(device);
|
||||||
|
CDeviceToken::TDeviceType type;
|
||||||
|
if (!strcmp(dt, "usb_device"))
|
||||||
|
type = CDeviceToken::DEVTYPE_USB;
|
||||||
|
else if (!strcmp(dt, "bluetooth_device"))
|
||||||
|
type = CDeviceToken::DEVTYPE_BLUETOOTH;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Prevent redundant registration */
|
||||||
const char* devPath = udev_device_get_syspath(device);
|
const char* devPath = udev_device_get_syspath(device);
|
||||||
if (listener->m_finder._hasToken(devPath))
|
if (listener->m_finder._hasToken(devPath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
udev_device* devCast =
|
|
||||||
udev_device_get_parent_with_subsystem_devtype(device, "bluetooth", "bluetooth_device");
|
|
||||||
if (!devCast)
|
|
||||||
devCast = udev_device_get_parent_with_subsystem_devtype(device, "usb", "usb_device");
|
|
||||||
if (!devCast)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int vid = 0, pid = 0;
|
int vid = 0, pid = 0;
|
||||||
udev_list_entry* attrs = udev_device_get_properties_list_entry(devCast);
|
udev_list_entry* attrs = udev_device_get_properties_list_entry(device);
|
||||||
|
#if 0
|
||||||
|
udev_list_entry* att = NULL;
|
||||||
|
udev_list_entry_foreach(att, attrs)
|
||||||
|
{
|
||||||
|
const char* name = udev_list_entry_get_name(att);
|
||||||
|
const char* val = udev_list_entry_get_value(att);
|
||||||
|
fprintf(stderr, "%s %s\n", name, val);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
udev_list_entry* vide = udev_list_entry_get_by_name(attrs, "ID_VENDOR_ID");
|
udev_list_entry* vide = udev_list_entry_get_by_name(attrs, "ID_VENDOR_ID");
|
||||||
if (vide)
|
if (vide)
|
||||||
|
@ -62,7 +76,36 @@ class CHIDListenerUdev final : public IHIDListener
|
||||||
if (producte)
|
if (producte)
|
||||||
product = udev_list_entry_get_value(producte);
|
product = udev_list_entry_get_value(producte);
|
||||||
|
|
||||||
listener->m_finder._insertToken(CDeviceToken(vid, pid, manuf, product, devPath));
|
if (!listener->m_finder._insertToken(CDeviceToken(type, vid, pid, manuf, product, devPath)))
|
||||||
|
{
|
||||||
|
/* Matched-insertion failed; see if generic HID interface is available */
|
||||||
|
udev_list_entry* devInterfaces = NULL;
|
||||||
|
if (type == CDeviceToken::DEVTYPE_USB)
|
||||||
|
devInterfaces = udev_list_entry_get_by_name(attrs, "ID_USB_INTERFACES");
|
||||||
|
else if (type == CDeviceToken::DEVTYPE_BLUETOOTH)
|
||||||
|
devInterfaces = udev_list_entry_get_by_name(attrs, "ID_BLUETOOTH_INTERFACES");
|
||||||
|
if (devInterfaces)
|
||||||
|
{
|
||||||
|
const char* interfacesStr = udev_list_entry_get_value(devInterfaces);
|
||||||
|
if (strstr(interfacesStr, ":030104") || /* HID / GenericDesktop / Joystick */
|
||||||
|
strstr(interfacesStr, ":030105")) /* HID / GenericDesktop / Gamepad */
|
||||||
|
{
|
||||||
|
udev_enumerate* hidEnum = udev_enumerate_new(UDEV_INST);
|
||||||
|
udev_enumerate_add_match_parent(hidEnum, device);
|
||||||
|
udev_enumerate_add_match_subsystem(hidEnum, "hid");
|
||||||
|
udev_enumerate_scan_devices(hidEnum);
|
||||||
|
udev_list_entry* hidEnt = udev_enumerate_get_list_entry(hidEnum);
|
||||||
|
if (hidEnt)
|
||||||
|
{
|
||||||
|
const char* hidPath = udev_list_entry_get_name(hidEnt);
|
||||||
|
if (!listener->m_finder._hasToken(hidPath))
|
||||||
|
listener->m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_GENERICHID,
|
||||||
|
vid, pid, manuf, product, hidPath));
|
||||||
|
}
|
||||||
|
udev_enumerate_unref(hidEnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deviceDisconnected(CHIDListenerUdev* listener,
|
static void deviceDisconnected(CHIDListenerUdev* listener,
|
||||||
|
@ -87,13 +130,9 @@ class CHIDListenerUdev final : public IHIDListener
|
||||||
{
|
{
|
||||||
const char* action = udev_device_get_action(dev);
|
const char* action = udev_device_get_action(dev);
|
||||||
if (!strcmp(action, "add"))
|
if (!strcmp(action, "add"))
|
||||||
{
|
|
||||||
deviceConnected(listener, dev);
|
deviceConnected(listener, dev);
|
||||||
}
|
|
||||||
else if (!strcmp(action, "remove"))
|
else if (!strcmp(action, "remove"))
|
||||||
{
|
|
||||||
deviceDisconnected(listener, dev);
|
deviceDisconnected(listener, dev);
|
||||||
}
|
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +147,8 @@ public:
|
||||||
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
|
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
|
||||||
if (!m_udevMon)
|
if (!m_udevMon)
|
||||||
throw std::runtime_error("unable to init udev_monitor");
|
throw std::runtime_error("unable to init udev_monitor");
|
||||||
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "hid", NULL);
|
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "usb", "usb_device");
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "bluetooth", "bluetooth_device");
|
||||||
udev_monitor_filter_update(m_udevMon);
|
udev_monitor_filter_update(m_udevMon);
|
||||||
|
|
||||||
/* Initial HID Device Add */
|
/* Initial HID Device Add */
|
||||||
|
@ -146,7 +186,10 @@ public:
|
||||||
bool scanNow()
|
bool scanNow()
|
||||||
{
|
{
|
||||||
udev_enumerate* uenum = udev_enumerate_new(GetUdev());
|
udev_enumerate* uenum = udev_enumerate_new(GetUdev());
|
||||||
udev_enumerate_add_match_subsystem(uenum, "hid");
|
udev_enumerate_add_match_subsystem(uenum, "usb");
|
||||||
|
udev_enumerate_add_match_property(uenum, "DEVTYPE", "usb_device");
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "bluetooth");
|
||||||
|
udev_enumerate_add_match_property(uenum, "DEVTYPE", "bluetooth_device");
|
||||||
udev_enumerate_scan_devices(uenum);
|
udev_enumerate_scan_devices(uenum);
|
||||||
udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);
|
udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);
|
||||||
udev_list_entry* uenumItem;
|
udev_list_entry* uenumItem;
|
||||||
|
|
|
@ -10,9 +10,9 @@ class IHIDDevice
|
||||||
{
|
{
|
||||||
friend class CDeviceBase;
|
friend class CDeviceBase;
|
||||||
virtual void _deviceDisconnected()=0;
|
virtual void _deviceDisconnected()=0;
|
||||||
virtual bool _sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)=0;
|
virtual bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)=0;
|
||||||
virtual size_t _receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0;
|
virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0;
|
||||||
virtual bool _sendReport(const uint8_t* data, size_t length)=0;
|
virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0;
|
||||||
public:
|
public:
|
||||||
inline virtual ~IHIDDevice() {};
|
inline virtual ~IHIDDevice() {};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "inputdev/SDeviceSignature.hpp"
|
#include "inputdev/SDeviceSignature.hpp"
|
||||||
#include "inputdev/CDeviceToken.hpp"
|
#include "inputdev/CDeviceToken.hpp"
|
||||||
|
#include "inputdev/CGenericPad.hpp"
|
||||||
#include "IHIDDevice.hpp"
|
#include "IHIDDevice.hpp"
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
|
@ -10,6 +11,8 @@ extern const SDeviceSignature BOO_DEVICE_SIGS[];
|
||||||
|
|
||||||
bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet)
|
bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet)
|
||||||
{
|
{
|
||||||
|
if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID)
|
||||||
|
return true;
|
||||||
for (const SDeviceSignature* sig : sigSet)
|
for (const SDeviceSignature* sig : sigSet)
|
||||||
{
|
{
|
||||||
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
|
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
|
||||||
|
@ -18,11 +21,29 @@ bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDevice
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel);
|
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp);
|
||||||
CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
|
CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
|
||||||
{
|
{
|
||||||
|
|
||||||
CDeviceBase* retval = NULL;
|
CDeviceBase* retval = NULL;
|
||||||
|
|
||||||
|
/* Early-return for generic HID devices */
|
||||||
|
if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID)
|
||||||
|
{
|
||||||
|
retval = new CGenericPad(&token);
|
||||||
|
if (!retval)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
IHIDDevice* newDev = IHIDDeviceNew(token, *retval);
|
||||||
|
if (!newDev)
|
||||||
|
{
|
||||||
|
delete retval;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise perform signature-matching to find the appropriate device-factory */
|
||||||
const SDeviceSignature* foundSig = NULL;
|
const SDeviceSignature* foundSig = NULL;
|
||||||
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
|
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
|
||||||
unsigned targetVid = token.getVendorId();
|
unsigned targetVid = token.getVendorId();
|
||||||
|
@ -43,7 +64,7 @@ CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
|
||||||
if (!retval)
|
if (!retval)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
IHIDDevice* newDev = IHIDDeviceNew(token, *retval, foundSig->m_lowLevel);
|
IHIDDevice* newDev = IHIDDeviceNew(token, *retval);
|
||||||
if (!newDev)
|
if (!newDev)
|
||||||
{
|
{
|
||||||
delete retval;
|
delete retval;
|
||||||
|
|
Loading…
Reference in New Issue