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[] =
|
||||
{
|
||||
DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337, true),
|
||||
DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337),
|
||||
DEVICE_SIG_SENTINEL()
|
||||
};
|
||||
|
||||
|
|
|
@ -27,14 +27,14 @@ public:
|
|||
virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);}
|
||||
|
||||
/* Low-Level API */
|
||||
bool sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length);
|
||||
size_t receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length);
|
||||
bool sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length);
|
||||
size_t receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length);
|
||||
virtual void initialCycle() {}
|
||||
virtual void transferCycle() {}
|
||||
virtual void finalCycle() {}
|
||||
|
||||
/* 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;}
|
||||
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@ private:
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
inline void _insertToken(CDeviceToken&& token)
|
||||
inline bool _insertToken(CDeviceToken&& token)
|
||||
{
|
||||
if (SDeviceSignature::DeviceMatchToken(token, m_types)) {
|
||||
m_tokensLock.lock();
|
||||
|
@ -52,7 +52,9 @@ private:
|
|||
m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token)));
|
||||
m_tokensLock.unlock();
|
||||
deviceConnected(inseredTok.first->second);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline void _removeToken(const std::string& path)
|
||||
{
|
||||
|
|
|
@ -10,6 +10,17 @@ namespace boo
|
|||
|
||||
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_productId;
|
||||
std::string m_vendorName;
|
||||
|
@ -28,10 +39,11 @@ class CDeviceToken
|
|||
}
|
||||
|
||||
public:
|
||||
|
||||
CDeviceToken(const CDeviceToken&) = delete;
|
||||
CDeviceToken(CDeviceToken&&) = default;
|
||||
inline CDeviceToken(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)
|
||||
inline CDeviceToken(enum TDeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path)
|
||||
: m_devType(devType), m_vendorId(vid), m_productId(pid), m_devPath(path), m_connectedDev(NULL)
|
||||
{
|
||||
if (vname)
|
||||
m_vendorName = vname;
|
||||
|
@ -39,6 +51,7 @@ public:
|
|||
m_productName = pname;
|
||||
}
|
||||
|
||||
inline TDeviceType getDeviceType() const {return m_devType;}
|
||||
inline unsigned getVendorId() const {return m_vendorId;}
|
||||
inline unsigned getProductId() const {return m_productId;}
|
||||
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_rumbleRequest;
|
||||
uint8_t m_rumbleState;
|
||||
bool m_didHandshake;
|
||||
void deviceDisconnected();
|
||||
void initialCycle();
|
||||
void transferCycle();
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
#ifndef CGENERICPAD_HPP
|
||||
#define CGENERICPAD_HPP
|
||||
|
||||
#include "CDeviceBase.hpp"
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
class CGenericPad final : public CDeviceBase
|
||||
{
|
||||
public:
|
||||
CGenericPad(CDeviceToken* token);
|
||||
~CGenericPad();
|
||||
|
||||
void deviceDisconnected();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CGENERICPAD_HPP
|
||||
|
|
|
@ -16,17 +16,16 @@ struct SDeviceSignature
|
|||
typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda;
|
||||
const char* m_name;
|
||||
unsigned m_vid, m_pid;
|
||||
bool m_lowLevel;
|
||||
TFactoryLambda m_factory;
|
||||
SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */
|
||||
SDeviceSignature(const char* name, unsigned vid, unsigned pid, bool lowLevel, TFactoryLambda&& factory)
|
||||
: m_name(name), m_vid(vid), m_pid(pid), m_lowLevel(lowLevel), m_factory(factory) {}
|
||||
SDeviceSignature(const char* name, unsigned vid, unsigned pid, TFactoryLambda&& factory)
|
||||
: m_name(name), m_vid(vid), m_pid(pid), m_factory(factory) {}
|
||||
static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet);
|
||||
static CDeviceBase* DeviceNew(CDeviceToken& token);
|
||||
};
|
||||
|
||||
#define DEVICE_SIG(name, vid, pid, lowLevel) \
|
||||
SDeviceSignature(#name, vid, pid, lowLevel, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
|
||||
#define DEVICE_SIG(name, vid, pid) \
|
||||
SDeviceSignature(#name, vid, pid, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
|
||||
#define DEVICE_SIG_SENTINEL() SDeviceSignature()
|
||||
|
||||
extern const SDeviceSignature BOO_DEVICE_SIGS[];
|
||||
|
|
|
@ -33,24 +33,24 @@ void CDeviceBase::closeDevice()
|
|||
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)
|
||||
return m_hidDev->_sendInterruptTransfer(pipe, data, length);
|
||||
return m_hidDev->_sendUSBInterruptTransfer(pipe, data, length);
|
||||
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)
|
||||
return m_hidDev->_receiveInterruptTransfer(pipe, data, length);
|
||||
return m_hidDev->_receiveUSBInterruptTransfer(pipe, data, length);
|
||||
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)
|
||||
return m_hidDev->_sendReport(data, length);
|
||||
return m_hidDev->_sendHIDReport(data, length);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ CDolphinSmashAdapter::CDolphinSmashAdapter(CDeviceToken* token)
|
|||
m_callback(NULL),
|
||||
m_knownControllers(0),
|
||||
m_rumbleRequest(0),
|
||||
m_rumbleState(0),
|
||||
m_didHandshake(false)
|
||||
m_rumbleState(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -23,8 +22,6 @@ CDolphinSmashAdapter::~CDolphinSmashAdapter()
|
|||
{
|
||||
}
|
||||
|
||||
static const uint8_t HANDSHAKE_PAYLOAD[] = {0x13};
|
||||
|
||||
static inline EDolphinControllerType parseType(unsigned char status)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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)))
|
||||
return;
|
||||
//printf("SENT HANDSHAKE %d\n", res);
|
||||
m_didHandshake = true;
|
||||
SDolphinControllerState state;
|
||||
bool rumble = false;
|
||||
EDolphinControllerType type = parseState(&state, controller, rumble);
|
||||
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];
|
||||
size_t recvSz = receiveInterruptTransfer(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)
|
||||
uint8_t rumbleMessage[5] = {0x11};
|
||||
for (int i=0 ; i<4 ; ++i)
|
||||
{
|
||||
SDolphinControllerState state;
|
||||
bool rumble = false;
|
||||
EDolphinControllerType type = parseState(&state, controller, rumble);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if (rumbleReq & 1<<i)
|
||||
rumbleMessage[i+1] = 1;
|
||||
else
|
||||
rumbleMessage[i+1] = 0;
|
||||
}
|
||||
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
||||
m_rumbleState = rumbleReq;
|
||||
}
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::initialCycle()
|
||||
{
|
||||
|
||||
uint8_t handshakePayload[] = {0x13};
|
||||
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload));
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::finalCycle()
|
||||
{
|
||||
if (m_didHandshake)
|
||||
{
|
||||
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
||||
sendInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
||||
}
|
||||
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
||||
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::deviceDisconnected()
|
||||
|
|
|
@ -1 +1,23 @@
|
|||
#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;
|
||||
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)
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
|||
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)
|
||||
{
|
||||
|
@ -215,7 +215,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
|||
m_runningTransferLoop = false;
|
||||
}
|
||||
|
||||
bool _sendReport(const uint8_t* data, size_t length)
|
||||
bool _sendHIDReport(const uint8_t* data, size_t length)
|
||||
{
|
||||
if (m_runLoop)
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
|
|||
|
||||
public:
|
||||
|
||||
CHIDDeviceIOKit(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel)
|
||||
CHIDDeviceIOKit(CDeviceToken& token, CDeviceBase& devImp)
|
||||
: m_token(token),
|
||||
m_devImp(devImp),
|
||||
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::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)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ class CHIDDeviceUdev final : public IHIDDevice
|
|||
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)
|
||||
{
|
||||
|
@ -75,15 +75,14 @@ class CHIDDeviceUdev final : public IHIDDevice
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void _threadProcLL(CHIDDeviceUdev* device)
|
||||
static void _threadProcUSBLL(CHIDDeviceUdev* device)
|
||||
{
|
||||
unsigned i;
|
||||
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) */
|
||||
udev_device* usbDev = udev_device_get_parent_with_subsystem_devtype(hidDev, "usb", "usb_device");
|
||||
const char* dp = udev_device_get_devnode(usbDev);
|
||||
const char* dp = udev_device_get_devnode(udevDev);
|
||||
device->m_devFd = open(dp, O_RDWR);
|
||||
if (device->m_devFd < 0)
|
||||
{
|
||||
|
@ -93,7 +92,7 @@ class CHIDDeviceUdev final : public IHIDDevice
|
|||
device->m_devImp.deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
udev_device_unref(hidDev);
|
||||
udev_device_unref(udevDev);
|
||||
return;
|
||||
}
|
||||
usb_device_descriptor devDesc = {0};
|
||||
|
@ -147,13 +146,46 @@ class CHIDDeviceUdev final : public IHIDDevice
|
|||
/* Cleanup */
|
||||
close(device->m_devFd);
|
||||
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()
|
||||
|
@ -161,24 +193,29 @@ class CHIDDeviceUdev final : public IHIDDevice
|
|||
m_runningTransferLoop = false;
|
||||
}
|
||||
|
||||
bool _sendReport(const uint8_t* data, size_t length)
|
||||
bool _sendHIDReport(const uint8_t* data, size_t length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
CHIDDeviceUdev(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel)
|
||||
CHIDDeviceUdev(CDeviceToken& token, CDeviceBase& devImp)
|
||||
: m_token(token),
|
||||
m_devImp(devImp),
|
||||
m_devPath(token.getDevicePath())
|
||||
{
|
||||
devImp.m_hidDev = this;
|
||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||
if (lowLevel)
|
||||
m_thread = new std::thread(_threadProcLL, this);
|
||||
CDeviceToken::TDeviceType dType = token.getDeviceType();
|
||||
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
|
||||
m_thread = new std::thread(_threadProcHL, this);
|
||||
throw std::runtime_error("invalid token supplied to device constructor");
|
||||
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)
|
||||
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);
|
||||
if (listener->m_finder._hasToken(devPath))
|
||||
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;
|
||||
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");
|
||||
if (vide)
|
||||
|
@ -62,7 +76,36 @@ class CHIDListenerUdev final : public IHIDListener
|
|||
if (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,
|
||||
|
@ -87,13 +130,9 @@ class CHIDListenerUdev final : public IHIDListener
|
|||
{
|
||||
const char* action = udev_device_get_action(dev);
|
||||
if (!strcmp(action, "add"))
|
||||
{
|
||||
deviceConnected(listener, dev);
|
||||
}
|
||||
else if (!strcmp(action, "remove"))
|
||||
{
|
||||
deviceDisconnected(listener, dev);
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +147,8 @@ public:
|
|||
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
|
||||
if (!m_udevMon)
|
||||
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);
|
||||
|
||||
/* Initial HID Device Add */
|
||||
|
@ -146,7 +186,10 @@ public:
|
|||
bool scanNow()
|
||||
{
|
||||
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_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);
|
||||
udev_list_entry* uenumItem;
|
||||
|
|
|
@ -10,9 +10,9 @@ class IHIDDevice
|
|||
{
|
||||
friend class CDeviceBase;
|
||||
virtual void _deviceDisconnected()=0;
|
||||
virtual bool _sendInterruptTransfer(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 bool _sendReport(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 _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0;
|
||||
virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0;
|
||||
public:
|
||||
inline virtual ~IHIDDevice() {};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "inputdev/SDeviceSignature.hpp"
|
||||
#include "inputdev/CDeviceToken.hpp"
|
||||
#include "inputdev/CGenericPad.hpp"
|
||||
#include "IHIDDevice.hpp"
|
||||
|
||||
namespace boo
|
||||
|
@ -10,6 +11,8 @@ extern const SDeviceSignature BOO_DEVICE_SIGS[];
|
|||
|
||||
bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet)
|
||||
{
|
||||
if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID)
|
||||
return true;
|
||||
for (const SDeviceSignature* sig : sigSet)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel);
|
||||
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp);
|
||||
CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
|
||||
{
|
||||
|
||||
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* sigIter = BOO_DEVICE_SIGS;
|
||||
unsigned targetVid = token.getVendorId();
|
||||
|
@ -43,7 +64,7 @@ CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
|
|||
if (!retval)
|
||||
return NULL;
|
||||
|
||||
IHIDDevice* newDev = IHIDDeviceNew(token, *retval, foundSig->m_lowLevel);
|
||||
IHIDDevice* newDev = IHIDDeviceNew(token, *retval);
|
||||
if (!newDev)
|
||||
{
|
||||
delete retval;
|
||||
|
|
Loading…
Reference in New Issue