diff --git a/include/boo/inputdev/HIDParser.hpp b/include/boo/inputdev/HIDParser.hpp index b860960..86553df 100644 --- a/include/boo/inputdev/HIDParser.hpp +++ b/include/boo/inputdev/HIDParser.hpp @@ -192,10 +192,11 @@ private: std::pair m_outputReports = {}; std::pair m_featureReports = {}; bool m_multipleReports = false; - ParserStatus ParseItem(HIDReports& reportsOut, - std::stack& stateStack, - std::stack& collectionStack, - const uint8_t*& it, const uint8_t* end); + static ParserStatus ParseItem(HIDReports& reportsOut, + std::stack& stateStack, + std::stack& 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 GetApplicationUsage(const uint8_t* descriptorData, size_t len); #endif operator bool() const { return m_status == ParserStatus::Done; } void EnumerateValues(const std::function& valueCB) const; diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index 36a2eb4..956de31 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -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 diff --git a/lib/inputdev/HIDDeviceUdev.cpp b/lib/inputdev/HIDDeviceUdev.cpp index 45c674f..5f0a8a0 100644 --- a/lib/inputdev/HIDDeviceUdev.cpp +++ b/lib/inputdev/HIDDeviceUdev.cpp @@ -16,6 +16,7 @@ #include #include #include +#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 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 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 device) { std::unique_lock 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 device) { char errStr[256]; std::unique_lock 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 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 _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 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& devImp) : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) @@ -286,11 +327,11 @@ public: std::unique_lock 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(shared_from_this())); else if (dType == DeviceType::Bluetooth) - m_thread = std::thread(_threadProcBTLL, this); + m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); else if (dType == DeviceType::HID) - m_thread = std::thread(_threadProcHID, this); + m_thread = std::thread(_threadProcHID, std::static_pointer_cast(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(); } diff --git a/lib/inputdev/HIDListenerIOKit.cpp b/lib/inputdev/HIDListenerIOKit.cpp index d43518b..7defca1 100644 --- a/lib/inputdev/HIDListenerIOKit.cpp +++ b/lib/inputdev/HIDListenerIOKit.cpp @@ -115,12 +115,8 @@ class HIDListenerIOKit : public IHIDListener getUSBStringDescriptor(dev, pstridx, pstr); } - if (!listener->m_finder._insertToken(std::make_unique(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(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(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(DeviceType::HID, + vidv, pidv, vstr, pstr, devPath)); //printf("ADDED %08X %s\n", obj, devPath); } diff --git a/lib/inputdev/HIDListenerUdev.cpp b/lib/inputdev/HIDListenerUdev.cpp index 824ce08..57b813a 100644 --- a/lib/inputdev/HIDListenerUdev.cpp +++ b/lib/inputdev/HIDListenerUdev.cpp @@ -1,9 +1,14 @@ #include "boo/inputdev/IHIDListener.hpp" #include "boo/inputdev/DeviceFinder.hpp" +#include "boo/inputdev/HIDParser.hpp" #include #include #include #include +#include +#include +#include +#include #include 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 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 */ diff --git a/lib/inputdev/HIDParser.cpp b/lib/inputdev/HIDParser.cpp index f5f9369..66859b6 100644 --- a/lib/inputdev/HIDParser.cpp +++ b/lib/inputdev/HIDParser.cpp @@ -481,7 +481,8 @@ HIDParser::ParserStatus HIDParser::ParseItem(HIDReports& reportsOut, std::stack& stateStack, std::stack& 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 stateStack; + stateStack.emplace(); + std::stack 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 HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len) +{ + std::stack stateStack; + stateStack.emplace(); + std::stack 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