better generic HID differentiation; smash udev working

This commit is contained in:
Jack Andersen 2015-04-30 13:17:46 -10:00
parent 4b8651b844
commit 1125e20b6e
15 changed files with 257 additions and 125 deletions

View File

@ -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()
}; };

View File

@ -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;}
}; };

View File

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

View File

@ -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;}

View File

@ -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();

View File

@ -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

View File

@ -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[];

View File

@ -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;
} }

View File

@ -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()

View File

@ -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()
{
}
}

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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;

View File

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

View File

@ -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;