mirror of https://github.com/AxioDL/boo.git
hidraw support for udev; fix race condition
This commit is contained in:
parent
ff89a9cccf
commit
7823aecc57
|
@ -60,6 +60,7 @@ std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token)
|
||||||
retval->m_hidDev = IHIDDeviceNew(token, *retval);
|
retval->m_hidDev = IHIDDeviceNew(token, *retval);
|
||||||
if (!retval->m_hidDev)
|
if (!retval->m_hidDev)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
retval->m_hidDev->_startThread();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +77,7 @@ std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token)
|
||||||
retval->m_hidDev = IHIDDeviceNew(token, *retval);
|
retval->m_hidDev = IHIDDeviceNew(token, *retval);
|
||||||
if (!retval->m_hidDev)
|
if (!retval->m_hidDev)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
retval->m_hidDev->_startThread();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,9 +341,13 @@ public:
|
||||||
: m_token(token),
|
: m_token(token),
|
||||||
m_devImp(devImp),
|
m_devImp(devImp),
|
||||||
m_devPath(token.getDevicePath())
|
m_devPath(token.getDevicePath())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startThread()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||||
DeviceType dType = token.getDeviceType();
|
DeviceType dType = m_token.getDeviceType();
|
||||||
if (dType == DeviceType::USB)
|
if (dType == DeviceType::USB)
|
||||||
m_thread = std::thread(_threadProcUSBLL, this);
|
m_thread = std::thread(_threadProcUSBLL, this);
|
||||||
else if (dType == DeviceType::Bluetooth)
|
else if (dType == DeviceType::Bluetooth)
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <stropts.h>
|
#include <stropts.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usbdevice_fs.h>
|
#include <linux/usbdevice_fs.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/hidraw.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -147,7 +149,6 @@ class HIDDeviceUdev final : public IHIDDevice
|
||||||
close(fd);
|
close(fd);
|
||||||
device->m_devFd = 0;
|
device->m_devFd = 0;
|
||||||
udev_device_unref(udevDev);
|
udev_device_unref(udevDev);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _threadProcBTLL(HIDDeviceUdev* device)
|
static void _threadProcBTLL(HIDDeviceUdev* device)
|
||||||
|
@ -171,20 +172,53 @@ class HIDDeviceUdev final : public IHIDDevice
|
||||||
|
|
||||||
static void _threadProcHID(HIDDeviceUdev* device)
|
static void _threadProcHID(HIDDeviceUdev* device)
|
||||||
{
|
{
|
||||||
|
char errStr[256];
|
||||||
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
||||||
udev_device* udevDev = 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 device file */
|
||||||
|
const char* dp = udev_device_get_devnode(udevDev);
|
||||||
|
int fd = open(dp, O_RDWR | O_NONBLOCK);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
|
||||||
|
device->m_token.getProductName().c_str(), dp, strerror(errno));
|
||||||
|
device->m_devImp.deviceError(errStr);
|
||||||
|
lk.unlock();
|
||||||
|
device->m_initCond.notify_one();
|
||||||
|
udev_device_unref(udevDev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
device->m_devFd = fd;
|
||||||
|
|
||||||
/* Return control to main thread */
|
/* Return control to main thread */
|
||||||
device->m_runningTransferLoop = true;
|
device->m_runningTransferLoop = true;
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
device->m_initCond.notify_one();
|
device->m_initCond.notify_one();
|
||||||
|
|
||||||
|
/* Report input size */
|
||||||
|
size_t readSz = device->m_devImp.getInputBufferSize();
|
||||||
|
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[readSz]);
|
||||||
|
|
||||||
/* Start transfer loop */
|
/* Start transfer loop */
|
||||||
device->m_devImp.initialCycle();
|
device->m_devImp.initialCycle();
|
||||||
while (device->m_runningTransferLoop)
|
while (device->m_runningTransferLoop)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
ssize_t sz = read(fd, readBuf.get(), readSz);
|
||||||
|
if (sz < 0)
|
||||||
|
break;
|
||||||
|
device->m_devImp.receivedHIDReport(readBuf.get(), sz,
|
||||||
|
HIDReportType::Input, readBuf[0]);
|
||||||
|
}
|
||||||
device->m_devImp.transferCycle();
|
device->m_devImp.transferCycle();
|
||||||
|
}
|
||||||
device->m_devImp.finalCycle();
|
device->m_devImp.finalCycle();
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
close(fd);
|
||||||
|
device->m_devFd = 0;
|
||||||
udev_device_unref(udevDev);
|
udev_device_unref(udevDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +227,26 @@ class HIDDeviceUdev final : public IHIDDevice
|
||||||
m_runningTransferLoop = false;
|
m_runningTransferLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message)
|
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
|
||||||
{
|
{
|
||||||
if (m_devFd)
|
if (m_devFd)
|
||||||
{
|
{
|
||||||
|
if (tp == HIDReportType::Feature)
|
||||||
|
{
|
||||||
|
int ret = ioctl(m_devFd, HIDIOCSFEATURE(length), data);
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (tp == HIDReportType::Output)
|
||||||
|
{
|
||||||
|
ssize_t ret = write(m_devFd, data, length);
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
usbdevfs_ctrltransfer xfer =
|
usbdevfs_ctrltransfer xfer =
|
||||||
{
|
{
|
||||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||||
|
@ -211,14 +261,25 @@ class HIDDeviceUdev final : public IHIDDevice
|
||||||
if (ret != (int)length)
|
if (ret != (int)length)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _recieveReport(const uint8_t *data, size_t length, uint16_t message)
|
size_t _receiveHIDReport(uint8_t *data, size_t length, HIDReportType tp, uint32_t message)
|
||||||
{
|
{
|
||||||
if (m_devFd)
|
if (m_devFd)
|
||||||
{
|
{
|
||||||
|
if (tp == HIDReportType::Feature)
|
||||||
|
{
|
||||||
|
data[0] = message;
|
||||||
|
int ret = ioctl(m_devFd, HIDIOCGFEATURE(length), data);
|
||||||
|
if (ret < 0)
|
||||||
|
return 0;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
usbdevfs_ctrltransfer xfer =
|
usbdevfs_ctrltransfer xfer =
|
||||||
{
|
{
|
||||||
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||||
|
@ -230,6 +291,7 @@ class HIDDeviceUdev final : public IHIDDevice
|
||||||
(void*)data
|
(void*)data
|
||||||
};
|
};
|
||||||
return ioctl(m_devFd, USBDEVFS_CONTROL, &xfer);
|
return ioctl(m_devFd, USBDEVFS_CONTROL, &xfer);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -241,14 +303,17 @@ public:
|
||||||
m_devImp(devImp),
|
m_devImp(devImp),
|
||||||
m_devPath(token.getDevicePath())
|
m_devPath(token.getDevicePath())
|
||||||
{
|
{
|
||||||
devImp.m_hidDev = this;
|
}
|
||||||
|
|
||||||
|
void _startThread()
|
||||||
|
{
|
||||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||||
DeviceToken::DeviceType dType = token.getDeviceType();
|
DeviceType dType = m_token.getDeviceType();
|
||||||
if (dType == DeviceToken::DeviceType::USB)
|
if (dType == DeviceType::USB)
|
||||||
m_thread = std::thread(_threadProcUSBLL, this);
|
m_thread = std::thread(_threadProcUSBLL, this);
|
||||||
else if (dType == DeviceToken::DeviceType::Bluetooth)
|
else if (dType == DeviceType::Bluetooth)
|
||||||
m_thread = std::thread(_threadProcBTLL, this);
|
m_thread = std::thread(_threadProcBTLL, this);
|
||||||
else if (dType == DeviceToken::DeviceType::GenericHID)
|
else if (dType == DeviceType::HID)
|
||||||
m_thread = std::thread(_threadProcHID, this);
|
m_thread = std::thread(_threadProcHID, this);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -268,9 +333,9 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDDevice* IHIDDeviceNew(DeviceToken& token, DeviceBase& devImp)
|
std::unique_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, DeviceBase& devImp)
|
||||||
{
|
{
|
||||||
return new HIDDeviceUdev(token, devImp);
|
return std::make_unique<HIDDeviceUdev>(token, devImp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,9 +325,13 @@ public:
|
||||||
: m_token(token),
|
: m_token(token),
|
||||||
m_devImp(devImp),
|
m_devImp(devImp),
|
||||||
m_devPath(token.getDevicePath())
|
m_devPath(token.getDevicePath())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startThread()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||||
DeviceType dType = token.getDeviceType();
|
DeviceType dType = m_token.getDeviceType();
|
||||||
if (dType == DeviceType::USB)
|
if (dType == DeviceType::USB)
|
||||||
m_thread = std::thread(_threadProcUSBLL, this);
|
m_thread = std::thread(_threadProcUSBLL, this);
|
||||||
else if (dType == DeviceType::Bluetooth)
|
else if (dType == DeviceType::Bluetooth)
|
||||||
|
|
|
@ -34,11 +34,11 @@ class HIDListenerUdev final : public IHIDListener
|
||||||
|
|
||||||
/* Filter to USB/BT */
|
/* Filter to USB/BT */
|
||||||
const char* dt = udev_device_get_devtype(device);
|
const char* dt = udev_device_get_devtype(device);
|
||||||
DeviceToken::DeviceType type;
|
DeviceType type;
|
||||||
if (!strcmp(dt, "usb_device"))
|
if (!strcmp(dt, "usb_device"))
|
||||||
type = DeviceToken::DeviceType::USB;
|
type = DeviceType::USB;
|
||||||
else if (!strcmp(dt, "bluetooth_device"))
|
else if (!strcmp(dt, "bluetooth_device"))
|
||||||
type = DeviceToken::DeviceType::Bluetooth;
|
type = DeviceType::Bluetooth;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -78,30 +78,30 @@ class HIDListenerUdev final : public IHIDListener
|
||||||
if (producte)
|
if (producte)
|
||||||
product = udev_list_entry_get_value(producte);
|
product = udev_list_entry_get_value(producte);
|
||||||
|
|
||||||
if (!listener->m_finder._insertToken(DeviceToken(type, vid, pid, manuf, product, devPath)))
|
if (!listener->m_finder._insertToken(
|
||||||
|
std::make_unique<DeviceToken>(type, vid, pid, manuf, product, devPath)))
|
||||||
{
|
{
|
||||||
/* Matched-insertion failed; see if generic HID interface is available */
|
/* Matched-insertion failed; see if generic HID interface is available */
|
||||||
udev_list_entry* devInterfaces = nullptr;
|
udev_list_entry* devInterfaces = nullptr;
|
||||||
if (type == DeviceToken::DeviceType::USB)
|
if (type == DeviceType::USB)
|
||||||
devInterfaces = udev_list_entry_get_by_name(attrs, "ID_USB_INTERFACES");
|
devInterfaces = udev_list_entry_get_by_name(attrs, "ID_USB_INTERFACES");
|
||||||
else if (type == DeviceToken::DeviceType::Bluetooth)
|
else if (type == DeviceType::Bluetooth)
|
||||||
devInterfaces = udev_list_entry_get_by_name(attrs, "ID_BLUETOOTH_INTERFACES");
|
devInterfaces = udev_list_entry_get_by_name(attrs, "ID_BLUETOOTH_INTERFACES");
|
||||||
if (devInterfaces)
|
if (devInterfaces)
|
||||||
{
|
{
|
||||||
const char* interfacesStr = udev_list_entry_get_value(devInterfaces);
|
const char* interfacesStr = udev_list_entry_get_value(devInterfaces);
|
||||||
if (strstr(interfacesStr, ":030104") || /* HID / GenericDesktop / Joystick */
|
if (strstr(interfacesStr, ":03")) /* HID */
|
||||||
strstr(interfacesStr, ":030105")) /* HID / GenericDesktop / Gamepad */
|
|
||||||
{
|
{
|
||||||
udev_enumerate* hidEnum = udev_enumerate_new(UDEV_INST);
|
udev_enumerate* hidEnum = udev_enumerate_new(UDEV_INST);
|
||||||
udev_enumerate_add_match_parent(hidEnum, device);
|
udev_enumerate_add_match_parent(hidEnum, device);
|
||||||
udev_enumerate_add_match_subsystem(hidEnum, "hid");
|
udev_enumerate_add_match_subsystem(hidEnum, "hidraw");
|
||||||
udev_enumerate_scan_devices(hidEnum);
|
udev_enumerate_scan_devices(hidEnum);
|
||||||
udev_list_entry* hidEnt = udev_enumerate_get_list_entry(hidEnum);
|
udev_list_entry* hidEnt = udev_enumerate_get_list_entry(hidEnum);
|
||||||
if (hidEnt)
|
if (hidEnt)
|
||||||
{
|
{
|
||||||
const char* hidPath = udev_list_entry_get_name(hidEnt);
|
const char* hidPath = udev_list_entry_get_name(hidEnt);
|
||||||
if (!listener->m_finder._hasToken(hidPath))
|
if (!listener->m_finder._hasToken(hidPath))
|
||||||
listener->m_finder._insertToken(DeviceToken(DeviceToken::DeviceType::GenericHID,
|
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID,
|
||||||
vid, pid, manuf, product, hidPath));
|
vid, pid, manuf, product, hidPath));
|
||||||
}
|
}
|
||||||
udev_enumerate_unref(hidEnum);
|
udev_enumerate_unref(hidEnum);
|
||||||
|
@ -230,9 +230,9 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDListener* IHIDListenerNew(DeviceFinder& finder)
|
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
|
||||||
{
|
{
|
||||||
return new HIDListenerUdev(finder);
|
return std::make_unique<HIDListenerUdev>(finder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,13 @@ namespace boo
|
||||||
class IHIDDevice
|
class IHIDDevice
|
||||||
{
|
{
|
||||||
friend class DeviceBase;
|
friend class DeviceBase;
|
||||||
|
friend struct DeviceSignature;
|
||||||
virtual void _deviceDisconnected()=0;
|
virtual void _deviceDisconnected()=0;
|
||||||
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0;
|
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0;
|
||||||
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0;
|
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0;
|
||||||
virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0;
|
virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0;
|
||||||
virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0;
|
virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0;
|
||||||
|
virtual void _startThread()=0;
|
||||||
public:
|
public:
|
||||||
inline virtual ~IHIDDevice() {}
|
inline virtual ~IHIDDevice() {}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue