From dfaac9e30f3902d2abd378205798a2f3a310600d Mon Sep 17 00:00:00 2001 From: Nav Date: Sat, 14 Jan 2023 03:03:10 +0000 Subject: [PATCH] Extract HID report size for EDBG debug tools via HID endpoint descriptor. Removed hidapi bodge (where we were mimicking the hid_device_ struct, to obtain the report size via `(hid_device_*)->input_ep_max_packet_size`). --- src/DebugToolDrivers/Microchip/EdbgDevice.cpp | 40 +++++++++++++++-- src/DebugToolDrivers/Microchip/EdbgDevice.hpp | 11 +++++ src/DebugToolDrivers/USB/HID/HidInterface.cpp | 17 +++----- src/DebugToolDrivers/USB/HID/HidInterface.hpp | 11 ++--- src/DebugToolDrivers/USB/HID/hidapi.hpp | 43 ------------------- src/DebugToolDrivers/USB/UsbDevice.cpp | 41 ++++++++++-------- src/DebugToolDrivers/USB/UsbDevice.hpp | 3 ++ 7 files changed, 84 insertions(+), 82 deletions(-) delete mode 100644 src/DebugToolDrivers/USB/HID/hidapi.hpp diff --git a/src/DebugToolDrivers/Microchip/EdbgDevice.cpp b/src/DebugToolDrivers/Microchip/EdbgDevice.cpp index ed3717ef..1685b8b5 100644 --- a/src/DebugToolDrivers/Microchip/EdbgDevice.cpp +++ b/src/DebugToolDrivers/Microchip/EdbgDevice.cpp @@ -30,14 +30,19 @@ namespace Bloom::DebugToolDrivers void EdbgDevice::init() { UsbDevice::init(); - auto cmsisHidInterface = Usb::HidInterface(this->cmsisHidInterfaceNumber, this->vendorId, this->productId); - - this->detachKernelDriverFromInterface(cmsisHidInterface.interfaceNumber); + this->detachKernelDriverFromInterface(this->cmsisHidInterfaceNumber); if (this->configurationIndex.has_value()) { this->setConfiguration(this->configurationIndex.value()); } + auto cmsisHidInterface = Usb::HidInterface( + this->cmsisHidInterfaceNumber, + this->getCmsisHidReportSize(), + this->vendorId, + this->productId + ); + cmsisHidInterface.init(); this->edbgInterface = std::make_unique(std::move(cmsisHidInterface)); @@ -125,4 +130,33 @@ namespace Bloom::DebugToolDrivers this->sessionStarted = false; } + + std::uint16_t EdbgDevice::getCmsisHidReportSize() { + const auto activeConfigDescriptor = this->getConfigDescriptor(); + + for (auto interfaceIndex = 0; interfaceIndex < activeConfigDescriptor->bNumInterfaces; ++interfaceIndex) { + const auto* interfaceDescriptor = (activeConfigDescriptor->interface + interfaceIndex)->altsetting; + + if (interfaceDescriptor->bInterfaceNumber != this->cmsisHidInterfaceNumber) { + continue; + } + + for (auto endpointIndex = 0; endpointIndex < activeConfigDescriptor->bNumInterfaces; ++endpointIndex) { + const auto* endpointDescriptor = (interfaceDescriptor->endpoint + endpointIndex); + + if ((endpointDescriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) != LIBUSB_ENDPOINT_IN) { + // Not an IN endpoint + continue; + } + + return endpointDescriptor->wMaxPacketSize; + } + } + + throw DeviceInitializationFailure( + "Failed to obtain CMSIS-DAP HID report size via endpoint descriptor - could not find IN endpoint for " + "selected configuration value (" + std::to_string(activeConfigDescriptor->bConfigurationValue) + + ") and interface number (" + std::to_string(this->cmsisHidInterfaceNumber) + ")" + ); + } } diff --git a/src/DebugToolDrivers/Microchip/EdbgDevice.hpp b/src/DebugToolDrivers/Microchip/EdbgDevice.hpp index 00847405..c6d273dd 100644 --- a/src/DebugToolDrivers/Microchip/EdbgDevice.hpp +++ b/src/DebugToolDrivers/Microchip/EdbgDevice.hpp @@ -142,5 +142,16 @@ namespace Bloom::DebugToolDrivers > targetPowerManagementInterface = nullptr; bool sessionStarted = false; + + /** + * Because EDBG devices require fixed-length reports to be transmitted to/from their HID interface, we must + * know the HID report size (as it differs across EDBG devices). + * + * This member function will obtain the report size from the endpoint descriptor of the IN endpoint, from the + * HID interface. + * + * @return + */ + std::uint16_t getCmsisHidReportSize(); }; } diff --git a/src/DebugToolDrivers/USB/HID/HidInterface.cpp b/src/DebugToolDrivers/USB/HID/HidInterface.cpp index ec9cabcc..b7a0b02b 100644 --- a/src/DebugToolDrivers/USB/HID/HidInterface.cpp +++ b/src/DebugToolDrivers/USB/HID/HidInterface.cpp @@ -9,9 +9,15 @@ namespace Bloom::Usb { using namespace Bloom::Exceptions; - HidInterface::HidInterface(std::uint8_t interfaceNumber, std::uint16_t vendorId, std::uint16_t productId) + HidInterface::HidInterface( + std::uint8_t interfaceNumber, + std::uint16_t inputReportSize, + std::uint16_t vendorId, + std::uint16_t productId + ) : interfaceNumber(interfaceNumber) , vendorId(vendorId) + , inputReportSize(inputReportSize) , productId(productId) {} @@ -27,15 +33,6 @@ namespace Bloom::Usb } this->hidDevice.reset(hidDevice); - - if (this->hidDevice->input_ep_max_packet_size < 1) { - throw DeviceInitializationFailure( - "Invalid max packet size for USB endpoint, on interface " - + std::to_string(this->interfaceNumber) - ); - } - - this->inputReportSize = static_cast(this->hidDevice->input_ep_max_packet_size); } void HidInterface::close() { diff --git a/src/DebugToolDrivers/USB/HID/HidInterface.hpp b/src/DebugToolDrivers/USB/HID/HidInterface.hpp index 0d656e6e..02cfecc7 100644 --- a/src/DebugToolDrivers/USB/HID/HidInterface.hpp +++ b/src/DebugToolDrivers/USB/HID/HidInterface.hpp @@ -7,7 +7,8 @@ #include #include -#include "hidapi.hpp" +#include +#include namespace Bloom::Usb { @@ -21,9 +22,11 @@ namespace Bloom::Usb { public: std::uint8_t interfaceNumber = 0; + std::uint16_t inputReportSize = 64; HidInterface( std::uint8_t interfaceNumber, + std::uint16_t inputReportSize, std::uint16_t vendorId, std::uint16_t productId ); @@ -72,12 +75,6 @@ namespace Bloom::Usb HidDevice hidDevice = HidDevice(nullptr, ::hid_close); - /** - * All HID reports have a fixed report length. This means that every packet we send or receive to/from an HID - * endpoint must be equal (in size) to the report length. - */ - std::size_t inputReportSize = 64; - std::uint16_t vendorId = 0; std::uint16_t productId = 0; }; diff --git a/src/DebugToolDrivers/USB/HID/hidapi.hpp b/src/DebugToolDrivers/USB/HID/hidapi.hpp deleted file mode 100644 index 22556aa8..00000000 --- a/src/DebugToolDrivers/USB/HID/hidapi.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -/* - * The code below was extracted from the HIDAPI library. Third-party license may apply here. - * - * https://github.com/signal11/hidapi - */ -struct hid_device_ -{ - // Handle to the actual device. - libusb_device_handle* device_handle; - - // Endpoint information - int input_endpoint; - int output_endpoint; - int input_ep_max_packet_size; - - // The interface number of the HID - int interface; - - // Indexes of Strings - int manufacturer_index; - int product_index; - int serial_index; - - // Whether blocking reads are used - int blocking; // boolean - - // Read thread objects - pthread_t thread; - pthread_mutex_t mutex; // Protects input_reports - pthread_cond_t condition; - pthread_barrier_t barrier; // Ensures correct start up sequence - int shutdown_thread; - int cancelled; - struct libusb_transfer* transfer; - - // List of received input reports. - struct input_report* input_reports; -}; diff --git a/src/DebugToolDrivers/USB/UsbDevice.cpp b/src/DebugToolDrivers/USB/UsbDevice.cpp index c310f9d1..1d3782be 100644 --- a/src/DebugToolDrivers/USB/UsbDevice.cpp +++ b/src/DebugToolDrivers/USB/UsbDevice.cpp @@ -56,26 +56,9 @@ namespace Bloom::Usb } void UsbDevice::setConfiguration(std::uint8_t configurationIndex) { - ::libusb_config_descriptor* configDescriptorPtr = {}; - auto libusbStatusCode = ::libusb_get_config_descriptor( - this->libusbDevice.get(), - configurationIndex, - &configDescriptorPtr - ); + const auto configDescriptor = this->getConfigDescriptor(configurationIndex); - if (libusbStatusCode < 0) { - throw DeviceInitializationFailure( - "Failed to obtain USB configuration descriptor - error code " + std::to_string(libusbStatusCode) - + " returned." - ); - } - - const auto configDescriptor = std::unique_ptr<::libusb_config_descriptor, decltype(&::libusb_free_config_descriptor)>( - configDescriptorPtr, - ::libusb_free_config_descriptor - ); - - libusbStatusCode = ::libusb_set_configuration( + const auto libusbStatusCode = ::libusb_set_configuration( this->libusbDeviceHandle.get(), configDescriptor->bConfigurationValue ); @@ -121,6 +104,26 @@ namespace Bloom::Usb return matchedDevices; } + LibusbConfigDescriptor UsbDevice::getConfigDescriptor(std::optional configurationIndex) { + ::libusb_config_descriptor* configDescriptor = {}; + + auto libusbStatusCode = configurationIndex.has_value() + ? ::libusb_get_config_descriptor(this->libusbDevice.get(), *configurationIndex, &configDescriptor) + : ::libusb_get_active_config_descriptor(this->libusbDevice.get(), &configDescriptor); + + if (libusbStatusCode < 0) { + throw DeviceInitializationFailure( + "Failed to obtain USB configuration descriptor - error code " + std::to_string(libusbStatusCode) + + " returned." + ); + } + + return LibusbConfigDescriptor( + configDescriptor, + ::libusb_free_config_descriptor + ); + } + void UsbDevice::detachKernelDriverFromInterface(std::uint8_t interfaceNumber) { const auto libusbStatusCode = ::libusb_kernel_driver_active(this->libusbDeviceHandle.get(), interfaceNumber); diff --git a/src/DebugToolDrivers/USB/UsbDevice.hpp b/src/DebugToolDrivers/USB/UsbDevice.hpp index 216d1e18..2ba353ce 100644 --- a/src/DebugToolDrivers/USB/UsbDevice.hpp +++ b/src/DebugToolDrivers/USB/UsbDevice.hpp @@ -13,6 +13,7 @@ namespace Bloom::Usb using LibusbContext = std::unique_ptr<::libusb_context, decltype(&::libusb_exit)>; using LibusbDevice = std::unique_ptr<::libusb_device, decltype(&::libusb_unref_device)>; using LibusbDeviceHandle = std::unique_ptr<::libusb_device_handle, decltype(&::libusb_close)>; + using LibusbConfigDescriptor = std::unique_ptr<::libusb_config_descriptor, decltype(&::libusb_free_config_descriptor)>; class UsbDevice { @@ -47,6 +48,8 @@ namespace Bloom::Usb std::vector findMatchingDevices(std::uint16_t vendorId, std::uint16_t productId); + LibusbConfigDescriptor getConfigDescriptor(std::optional configurationIndex = std::nullopt); + void detachKernelDriverFromInterface(std::uint8_t interfaceNumber); void close();