HID parser for udev; Vulkan fixes

This commit is contained in:
Jack Andersen 2017-09-15 15:55:41 -10:00
parent 1f14cc09a1
commit 175893f055
6 changed files with 175 additions and 46 deletions

View File

@ -192,10 +192,11 @@ private:
std::pair<uint32_t, uint32_t> m_outputReports = {};
std::pair<uint32_t, uint32_t> m_featureReports = {};
bool m_multipleReports = false;
ParserStatus ParseItem(HIDReports& reportsOut,
std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& collectionStack,
const uint8_t*& it, const uint8_t* end);
static ParserStatus ParseItem(HIDReports& reportsOut,
std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& collectionStack,
const uint8_t*& it, const uint8_t* end,
bool& multipleReports);
#endif
public:
@ -203,6 +204,8 @@ public:
ParserStatus Parse(const PHIDP_PREPARSED_DATA descriptorData);
#else
ParserStatus Parse(const uint8_t* descriptorData, size_t len);
static size_t CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len);
static std::pair<HIDUsagePage, HIDUsage> GetApplicationUsage(const uint8_t* descriptorData, size_t len);
#endif
operator bool() const { return m_status == ParserStatus::Done; }
void EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;

View File

@ -89,7 +89,7 @@ dbgFunc(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType,
const char *pLayerPrefix, const char *pMsg, void *pUserData)
{
if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
Log.report(logvisor::Fatal, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
Log.report(logvisor::Error, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
} else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
Log.report(logvisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
} else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
@ -339,7 +339,6 @@ void VulkanContext::initVulkan(const char* appName)
m_layerNames.push_back("VK_LAYER_LUNARG_core_validation");
m_layerNames.push_back("VK_LAYER_LUNARG_object_tracker");
m_layerNames.push_back("VK_LAYER_LUNARG_parameter_validation");
m_layerNames.push_back("VK_LAYER_LUNARG_swapchain");
m_layerNames.push_back("VK_LAYER_GOOGLE_threading");
#endif

View File

@ -16,6 +16,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include "boo/inputdev/HIDParser.hpp"
namespace boo
{
@ -29,7 +30,7 @@ udev* GetUdev();
class HIDDeviceUdev final : public IHIDDevice
{
DeviceToken& m_token;
DeviceBase& m_devImp;
std::shared_ptr<DeviceBase> m_devImp;
int m_devFd = 0;
unsigned m_usbIntfInPipe = 0;
@ -76,7 +77,7 @@ class HIDDeviceUdev final : public IHIDDevice
return 0;
}
static void _threadProcUSBLL(HIDDeviceUdev* device)
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceUdev> device)
{
int i;
char errStr[256];
@ -90,7 +91,7 @@ class HIDDeviceUdev final : public IHIDDevice
{
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().c_str(), dp, strerror(errno));
device->m_devImp.deviceError(errStr);
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
@ -140,10 +141,10 @@ class HIDDeviceUdev final : public IHIDDevice
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp.initialCycle();
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp.transferCycle();
device->m_devImp.finalCycle();
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
/* Cleanup */
close(fd);
@ -151,7 +152,7 @@ class HIDDeviceUdev final : public IHIDDevice
udev_device_unref(udevDev);
}
static void _threadProcBTLL(HIDDeviceUdev* device)
static void _threadProcBTLL(std::shared_ptr<HIDDeviceUdev> device)
{
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
@ -162,15 +163,17 @@ class HIDDeviceUdev final : public IHIDDevice
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp.initialCycle();
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp.transferCycle();
device->m_devImp.finalCycle();
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
udev_device_unref(udevDev);
}
static void _threadProcHID(HIDDeviceUdev* device)
int m_reportDescSz;
static void _threadProcHID(std::shared_ptr<HIDDeviceUdev> device)
{
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
@ -183,7 +186,7 @@ class HIDDeviceUdev final : public IHIDDevice
{
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().c_str(), dp, strerror(errno));
device->m_devImp.deviceError(errStr);
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
@ -196,12 +199,33 @@ class HIDDeviceUdev final : public IHIDDevice
lk.unlock();
device->m_initCond.notify_one();
/* Report input size */
size_t readSz = device->m_devImp.getInputBufferSize();
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
{
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n",
device->m_token.getProductName().c_str(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
close(fd);
return;
}
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1)
{
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n",
device->m_token.getProductName().c_str(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
close(fd);
return;
}
size_t readSz = HIDParser::CalculateMaxInputReportSize(reportDesc.value, reportDesc.size);
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[readSz]);
/* Start transfer loop */
device->m_devImp.initialCycle();
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
{
fd_set readset;
@ -215,13 +239,13 @@ class HIDDeviceUdev final : public IHIDDevice
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->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);
@ -234,6 +258,23 @@ class HIDDeviceUdev final : public IHIDDevice
m_runningTransferLoop = false;
}
std::vector<uint8_t> _getReportDescriptor()
{
/* Report descriptor size */
int reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
return {};
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESC, &reportDesc) == -1)
return {};
std::vector<uint8_t> ret(reportDesc.size, '\0');
memmove(ret.data(), reportDesc.value, reportDesc.size);
return ret;
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
if (m_devFd)
@ -274,7 +315,7 @@ class HIDDeviceUdev final : public IHIDDevice
public:
HIDDeviceUdev(DeviceToken& token, DeviceBase& devImp)
HIDDeviceUdev(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
@ -286,11 +327,11 @@ public:
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, this);
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, this);
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, this);
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else
{
fprintf(stderr, "invalid token supplied to device constructor");
@ -303,7 +344,7 @@ public:
{
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.join();
m_thread.detach();
}

View File

@ -115,12 +115,8 @@ class HIDListenerIOKit : public IHIDListener
getUSBStringDescriptor(dev, pstridx, pstr);
}
if (!listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB,
vid, pid, vstr, pstr, devPath)))
{
/* Matched-insertion failed; see if generic HID interface is available */
/* TODO: Do */
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB,
vid, pid, vstr, pstr, devPath));
//printf("ADDED %08X %s\n", obj, devPath);
}
@ -195,7 +191,7 @@ class HIDListenerIOKit : public IHIDListener
if (usageV != kHIDUsage_GD_Joystick && usageV != kHIDUsage_GD_GamePad)
continue;
}
else if (usagePageV != kHIDPage_Game)
else
{
continue;
}
@ -216,12 +212,8 @@ class HIDListenerIOKit : public IHIDListener
CFStringGetCString(pstridx.get(), pstr, 128, kCFStringEncodingUTF8);
}
if (!listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID,
vidv, pidv, vstr, pstr, devPath)))
{
/* Matched-insertion failed; see if generic HID interface is available */
/* TODO: Do */
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID,
vidv, pidv, vstr, pstr, devPath));
//printf("ADDED %08X %s\n", obj, devPath);
}

View File

@ -1,9 +1,14 @@
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
#include "boo/inputdev/HIDParser.hpp"
#include <libudev.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <thread>
namespace boo
@ -91,6 +96,38 @@ class HIDListenerUdev final : public IHIDListener
product = udev_list_entry_get_value(hidnamee);
manuf = product;
}
/* Get device file */
const char* dp = udev_device_get_devnode(device);
int fd = open(dp, O_RDWR);
if (fd < 0)
return;
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
{
const char* err = strerror(errno);
close(fd);
return;
}
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1)
{
const char* err = strerror(errno);
close(fd);
return;
}
close(fd);
std::pair<HIDUsagePage, HIDUsage> usage =
HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size);
if (usage.first != HIDUsagePage::GenericDesktop ||
(usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad))
return;
}
#if 0
@ -171,6 +208,7 @@ public:
}
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_add_match_subsystem_devtype(m_udevMon, "hidraw", nullptr);
udev_monitor_filter_update(m_udevMon);
/* Initial HID Device Add */

View File

@ -481,7 +481,8 @@ HIDParser::ParserStatus
HIDParser::ParseItem(HIDReports& reportsOut,
std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& collectionStack,
const uint8_t*& it, const uint8_t* end)
const uint8_t*& it, const uint8_t* end,
bool& multipleReports)
{
ParserStatus status = ParserStatus::OK;
uint8_t head = *it++;
@ -560,7 +561,7 @@ HIDParser::ParseItem(HIDReports& reportsOut,
stateStack.top().m_reportSize = data;
break;
case HIDItemTag::ReportID:
m_multipleReports = true;
multipleReports = true;
stateStack.top().m_reportID = data;
break;
case HIDItemTag::ReportCount:
@ -620,7 +621,8 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l
const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;)
if ((m_status = ParseItem(reports, stateStack, collectionStack, it, end)) != ParserStatus::OK)
if ((m_status =
ParseItem(reports, stateStack, collectionStack, it, end, m_multipleReports)) != ParserStatus::OK)
break;
if (m_status != ParserStatus::Done)
@ -660,6 +662,60 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l
return m_status;
}
size_t HIDParser::CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len)
{
std::stack<HIDItemState> stateStack;
stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack;
HIDReports reports;
ParserStatus status = ParserStatus::Done;
bool multipleReports = false;
const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;)
if ((status = ParseItem(reports, stateStack, collectionStack, it, end, multipleReports)) != ParserStatus::OK)
break;
if (status != ParserStatus::Done)
return 0;
size_t maxSize = 0;
for (const auto& rep : reports.m_inputReports)
{
size_t repSize = 0;
for (const auto& item : rep.second)
repSize += item.m_reportSize;
if (repSize > maxSize)
maxSize = repSize;
}
return (maxSize + 7) / 8 + multipleReports;
}
std::pair<HIDUsagePage, HIDUsage> HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len)
{
std::stack<HIDItemState> stateStack;
stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack;
HIDReports reports;
ParserStatus status = ParserStatus::Done;
bool multipleReports = false;
const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;)
{
status = ParseItem(reports, stateStack, collectionStack, it, end, multipleReports);
if (collectionStack.empty())
continue;
if (collectionStack.top().m_type == HIDCollectionType::Application)
return { collectionStack.top().m_usagePage, collectionStack.top().m_usage };
if (status != ParserStatus::OK)
break;
}
return {};
}
#endif
#if _WIN32