LibusbUtils: Add GetStringDescriptor function to return unicode strings and replace our libusb_get_string_descriptor_ascii calls.

This commit is contained in:
Jordan Woyak
2025-07-05 20:55:13 -05:00
parent a5e85caf0a
commit 13784f842e
4 changed files with 79 additions and 59 deletions

View File

@ -107,50 +107,15 @@ LibUSBBluetoothAdapter::LibUSBBluetoothAdapter()
if (IsBluetoothDevice(device_descriptor) && OpenDevice(device_descriptor, device))
{
unsigned char manufacturer[50] = {}, product[50] = {}, serial_number[50] = {};
const int manufacturer_ret = libusb_get_string_descriptor_ascii(
m_handle, device_descriptor.iManufacturer, manufacturer, sizeof(manufacturer));
if (manufacturer_ret < LIBUSB_SUCCESS)
{
WARN_LOG_FMT(IOS_WIIMOTE,
"Failed to get string for manufacturer descriptor {:02x} for device "
"{:04x}:{:04x} (rev {:x}): {}",
device_descriptor.iManufacturer, device_descriptor.idVendor,
device_descriptor.idProduct, device_descriptor.bcdDevice,
LibusbUtils::ErrorWrap(manufacturer_ret));
manufacturer[0] = '?';
manufacturer[1] = '\0';
}
const int product_ret = libusb_get_string_descriptor_ascii(
m_handle, device_descriptor.iProduct, product, sizeof(product));
if (product_ret < LIBUSB_SUCCESS)
{
WARN_LOG_FMT(IOS_WIIMOTE,
"Failed to get string for product descriptor {:02x} for device "
"{:04x}:{:04x} (rev {:x}): {}",
device_descriptor.iProduct, device_descriptor.idVendor,
device_descriptor.idProduct, device_descriptor.bcdDevice,
LibusbUtils::ErrorWrap(product_ret));
product[0] = '?';
product[1] = '\0';
}
const int serial_ret = libusb_get_string_descriptor_ascii(
m_handle, device_descriptor.iSerialNumber, serial_number, sizeof(serial_number));
if (serial_ret < LIBUSB_SUCCESS)
{
WARN_LOG_FMT(IOS_WIIMOTE,
"Failed to get string for serial number descriptor {:02x} for device "
"{:04x}:{:04x} (rev {:x}): {}",
device_descriptor.iSerialNumber, device_descriptor.idVendor,
device_descriptor.idProduct, device_descriptor.bcdDevice,
LibusbUtils::ErrorWrap(serial_ret));
serial_number[0] = '?';
serial_number[1] = '\0';
}
const auto manufacturer =
LibusbUtils::GetStringDescriptor(m_handle, device_descriptor.iManufacturer).value_or("?");
const auto product =
LibusbUtils::GetStringDescriptor(m_handle, device_descriptor.iProduct).value_or("?");
const auto serial_number =
LibusbUtils::GetStringDescriptor(m_handle, device_descriptor.iSerialNumber).value_or("?");
NOTICE_LOG_FMT(IOS_WIIMOTE, "Using device {:04x}:{:04x} (rev {:x}) for Bluetooth: {} {} {}",
device_descriptor.idVendor, device_descriptor.idProduct,
device_descriptor.bcdDevice, reinterpret_cast<char*>(manufacturer),
reinterpret_cast<char*>(product), reinterpret_cast<char*>(serial_number));
device_descriptor.bcdDevice, manufacturer, product, serial_number);
m_is_wii_bt_module =
device_descriptor.idVendor == 0x57e && device_descriptor.idProduct == 0x305;
return false;

View File

@ -114,27 +114,23 @@ std::string USBHost::GetDeviceNameFromVIDPID(u16 vid, u16 pid)
return device_name;
context.GetDeviceList([&device_name, vid, pid](libusb_device* device) {
libusb_device_descriptor desc;
libusb_device_descriptor desc{};
if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS)
return true;
if (desc.idVendor == vid && desc.idProduct == pid)
{
libusb_device_handle* handle;
if (libusb_open(device, &handle) == LIBUSB_SUCCESS)
{
unsigned char buffer[256];
if (desc.iProduct &&
libusb_get_string_descriptor_ascii(handle, desc.iProduct, buffer, sizeof(buffer)) > 0)
{
device_name = reinterpret_cast<char*>(buffer);
}
libusb_close(handle);
}
if (desc.idVendor != vid || desc.idProduct != pid)
return true;
if (desc.iProduct == 0)
return false;
}
return true;
libusb_device_handle* handle{};
if (libusb_open(device, &handle) != LIBUSB_SUCCESS)
return false;
device_name = LibusbUtils::GetStringDescriptor(handle, desc.iProduct).value_or("");
libusb_close(handle);
return false;
});
if (!device_name.empty())

View File

@ -12,6 +12,7 @@
#include "Common/Assert.h"
#include "Common/Flag.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h"
namespace LibusbUtils
@ -145,4 +146,54 @@ const char* ErrorWrap::GetStrError() const
return "__LIBUSB__ not defined";
#endif
}
std::optional<std::string> GetStringDescriptor(libusb_device_handle* dev_handle, uint8_t desc_index)
{
#if defined(__LIBUSB__)
struct StringDescriptor
{
u8 length;
u8 descriptor_type;
char16_t data[127];
};
StringDescriptor buffer{};
// Reading lang ID 0 returns a list of lang IDs.
const auto lang_id_result = libusb_get_string_descriptor(
dev_handle, desc_index, 0, reinterpret_cast<unsigned char*>(&buffer), 4);
if (lang_id_result != 4 || buffer.length < 4 || buffer.descriptor_type != LIBUSB_DT_STRING)
{
ERROR_LOG_FMT(IOS_USB, "libusb_get_string_descriptor(desc_index={}, lang_id=0) result:{}",
int(desc_index), lang_id_result);
return std::nullopt;
}
const u16 lang_id = buffer.data[0];
const auto str_result = libusb_get_string_descriptor(
dev_handle, desc_index, lang_id, reinterpret_cast<unsigned char*>(&buffer), 255);
if (str_result < 2 || buffer.length > str_result || buffer.descriptor_type != LIBUSB_DT_STRING)
{
ERROR_LOG_FMT(IOS_USB, "libusb_get_string_descriptor(desc_index={}, lang_id={}) result:{}",
int(desc_index), lang_id, str_result);
return std::nullopt;
}
// The UTF-16 data size should be even and equal to the return value.
if ((buffer.length & 1u) != 0 || buffer.length != str_result)
{
WARN_LOG_FMT(IOS_USB, "GetStringDescriptor: buffer.length:{} result:{}", buffer.length,
str_result);
}
const std::size_t str_length = std::max(0, buffer.length - 2) / 2;
return UTF16ToUTF8(std::u16string_view{buffer.data, str_length});
#else
return "__LIBUSB__ not defined";
#endif
}
} // namespace LibusbUtils

View File

@ -4,8 +4,10 @@
#pragma once
#include <fmt/format.h>
#include <functional>
#include <memory>
#include <optional>
#include <utility>
#include "Common/CommonTypes.h"
@ -13,6 +15,7 @@
struct libusb_config_descriptor;
struct libusb_context;
struct libusb_device;
struct libusb_device_handle;
namespace LibusbUtils
{
@ -53,6 +56,11 @@ struct ErrorWrap
const char* GetStrError() const;
const char* GetName() const;
};
// Returns the UTF-16 descriptor converted to UTF-8 or returns nullopt on error.
std::optional<std::string> GetStringDescriptor(libusb_device_handle* dev_handle,
uint8_t desc_index);
} // namespace LibusbUtils
template <>