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`).
This commit is contained in:
@@ -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<EdbgInterface>(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) + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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<std::size_t>(this->hidDevice->input_ep_max_packet_size);
|
||||
}
|
||||
|
||||
void HidInterface::close() {
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include <optional>
|
||||
#include <chrono>
|
||||
|
||||
#include "hidapi.hpp"
|
||||
#include <hidapi/hidapi.h>
|
||||
#include <hidapi/hidapi_libusb.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <hidapi/hidapi.h>
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
@@ -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<std::uint8_t> 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);
|
||||
|
||||
|
||||
@@ -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<LibusbDevice> findMatchingDevices(std::uint16_t vendorId, std::uint16_t productId);
|
||||
|
||||
LibusbConfigDescriptor getConfigDescriptor(std::optional<std::uint8_t> configurationIndex = std::nullopt);
|
||||
|
||||
void detachKernelDriverFromInterface(std::uint8_t interfaceNumber);
|
||||
|
||||
void close();
|
||||
|
||||
Reference in New Issue
Block a user