Devices: Extract USB descriptors

Shows most of the USB attributes by extracting the values in the
internal USB tree. This is meant to display the same information as
listusb -v.

Changes:
- Added FindDevicePath in DeviceUSB.cpp to map the device to their
  hardware path
- Added USBTree in DeviceUSB.cpp that goes through the configurations,
  interfaces, alternates and endpoints of USB devices to set new attributes
- Linked the path found in FindDevicePath to a BUSBDevice object, that
  is called in USBTree to start the extraction

Change-Id: I9fd314767dc856b3cc603346d88be438699429d9
Reviewed-on: https://review.haiku-os.org/c/haiku/+/11071
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Kacper Kasper <[email protected]>
This commit is contained in:
Leo Rouleau
2026-07-09 06:46:12 +00:00
committed by Adrien Destugues
parent 5bec7e6ebd
commit 3a517423b0
2 changed files with 188 additions and 8 deletions
+187 -7
View File
@@ -13,6 +13,10 @@
#include <stdlib.h>
#include <Catalog.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>
#include <USBKit.h>
#include <bus/USB.h>
#undef B_TRANSLATION_CONTEXT
@@ -24,6 +28,24 @@ extern "C" {
}
#define USB_SELF_POWERED 0x40
#define USB_REMOTE_WAKEUP 0x20
static uint8
MajorVersion(uint16 version)
{
return version >> 8;
}
static uint8
MinorVersion(uint16 version)
{
return version & 0xff;
}
DeviceUSB::DeviceUSB(Device* parent)
:
Device(parent),
@@ -47,6 +69,162 @@ static BString ToHex(uint16 num)
}
static BString
FindDevicePath(const char* currentPath, uint16 vendor, uint16 product)
{
BDirectory dir(currentPath);
if (dir.InitCheck() != B_OK)
return "";
BEntry entry;
while (dir.GetNextEntry(&entry) == B_OK) {
BPath pathObj;
entry.GetPath(&pathObj);
if (BString(pathObj.Leaf()) == "hub")
continue;
if (entry.IsDirectory()) {
BString result = FindDevicePath(pathObj.Path(), vendor, product);
if (result != "")
return result;
} else {
BUSBDevice testDevice(pathObj.Path());
if (testDevice.InitCheck() == B_OK && testDevice.VendorID() == vendor
&& testDevice.ProductID() == product) {
return BString(pathObj.Path());
}
}
}
return "";
}
static void
BuildUSBTree(BUSBDevice& device, DeviceUSB* node)
{
node->SetAttribute("usb/path", device.Location());
if (device.ManufacturerString())
node->SetAttribute("usb/manufacturer", device.ManufacturerString());
if (device.ProductString())
node->SetAttribute("usb/product", device.ProductString());
if (device.SerialNumberString())
node->SetAttribute("usb/serial_number", device.SerialNumberString());
BString usbVersion;
usbVersion.SetToFormat(B_TRANSLATE("%d.%d"),
MajorVersion(device.USBVersion()),
MinorVersion(device.USBVersion()));
node->SetAttribute("usb/version", usbVersion);
for (uint32 i = 0; i < device.CountConfigurations(); i++) {
const BUSBConfiguration* config = device.ConfigurationAt(i);
if (!config)
continue;
BString confPath;
confPath << "usb/config/" << i;
BString powerValue;
powerValue.SetToFormat(B_TRANSLATE("%d mA"), config->Descriptor()->max_power * 2);
node->SetAttribute(BString(confPath) << "/max_power", powerValue);
uint8 attr = config->Descriptor()->attributes;
if (attr & USB_SELF_POWERED)
node->SetAttribute(BString(confPath) << "/self_powered", "true");
if (attr & USB_REMOTE_WAKEUP)
node->SetAttribute(BString(confPath) << "/remote_wakeup", "true");
if (config->ConfigurationString())
node->SetAttribute(BString(confPath) << "/name", config->ConfigurationString());
for (uint32 j = 0; j < config->CountInterfaces(); j++) {
const BUSBInterface* interface = config->InterfaceAt(j);
if (!interface)
continue;
BString intfPath;
intfPath << confPath << "/interface/" << j;
for (uint32 k = 0; k < interface->CountAlternates(); k++) {
const BUSBInterface* alt = interface->AlternateAt(k);
if (!alt)
continue;
BString altPath;
altPath << intfPath << "/alt/" << k;
if (k == interface->AlternateIndex())
node->SetAttribute(BString(altPath) << "/active", "true");
char classInfo[128];
usb_get_class_info(alt->Class(), alt->Subclass(), alt->Protocol(), classInfo,
sizeof(classInfo));
BString classVal;
classVal.SetToFormat(B_TRANSLATE("0x%02x, Sub: 0x%02x (%s)"), alt->Class(),
alt->Subclass(), classInfo);
node->SetAttribute(BString(altPath) << "/class_info", classVal);
if (alt->InterfaceString())
node->SetAttribute(BString(altPath) << "/name", alt->InterfaceString());
for (uint32 e = 0; e < alt->CountEndpoints(); e++) {
const BUSBEndpoint* endpoint = alt->EndpointAt(e);
if (!endpoint)
continue;
BString endpointPath;
endpointPath << altPath << "/endpoint/" << e;
const usb_endpoint_descriptor* endpointDesc = endpoint->Descriptor();
BString endpointAddress;
endpointAddress.SetToFormat(B_TRANSLATE("0x%02x (%s)"),
endpointDesc->endpoint_address,
(endpointDesc->endpoint_address & USB_ENDPOINT_ADDR_DIR_MASK)
== USB_ENDPOINT_ADDR_DIR_IN
? B_TRANSLATE("IN")
: B_TRANSLATE("OUT"));
node->SetAttribute(BString(endpointPath) << "/address", endpointAddress);
const char* type = B_TRANSLATE("Unknown");
switch (endpointDesc->attributes & USB_ENDPOINT_ATTR_MASK) {
case USB_ENDPOINT_ATTR_CONTROL:
type = B_TRANSLATE("Control");
break;
case USB_ENDPOINT_ATTR_ISOCHRONOUS:
type = B_TRANSLATE("Isochronous");
break;
case USB_ENDPOINT_ATTR_BULK:
type = B_TRANSLATE("Bulk");
break;
case USB_ENDPOINT_ATTR_INTERRUPT:
type = B_TRANSLATE("Interrupt");
break;
}
node->SetAttribute(BString(endpointPath) << "/type", type);
BString maxPacket;
maxPacket << endpointDesc->max_packet_size;
node->SetAttribute(BString(endpointPath) << "/max_packet_size", maxPacket);
if ((endpointDesc->attributes & USB_ENDPOINT_ATTR_MASK)
== USB_ENDPOINT_ATTR_INTERRUPT) {
BString interval;
interval.SetToFormat(B_TRANSLATE("%u ms"), endpointDesc->interval);
node->SetAttribute(BString(endpointPath) << "/interval", interval);
}
}
}
}
}
}
void
DeviceUSB::InitFromAttributes()
{
@@ -91,13 +269,6 @@ DeviceUSB::InitFromAttributes()
SetAttribute(B_TRANSLATE("Device name"), deviceLabel);
SetAttribute(B_TRANSLATE("Manufacturer"), manufacturerLabel);
#if 0
// These are a source of confusion for users, leading them to think there
// is no driver for their device. Until we can display something useful,
// let's not show the lines at all.
SetAttribute(B_TRANSLATE("Driver used"), B_TRANSLATE("Not implemented"));
SetAttribute(B_TRANSLATE("Device paths"), B_TRANSLATE("Not implemented"));
#endif
SetAttribute(B_TRANSLATE("Class info"), classInfo);
switch (fClassBaseId) {
case 0x1:
@@ -124,4 +295,13 @@ DeviceUSB::InitFromAttributes()
BString outlineName;
outlineName << manufacturerLabel << " " << deviceLabel;
SetText(outlineName.String());
// Fetch USB attributes
BString path = FindDevicePath("/dev/bus/usb/", fVendorId, fDeviceId);
if (path.Length() > 0) {
BUSBDevice device(path.String());
if (device.InitCheck() == B_OK)
BuildUSBTree(device, this);
}
}
+1 -1
View File
@@ -99,7 +99,7 @@ Application Devices :
DeviceUSB.cpp
Device.cpp
PropertyList.cpp
: be libcolumnlistview.a tracker [ TargetLibsupc++ ]
: be device libcolumnlistview.a tracker [ TargetLibsupc++ ]
[ TargetLibstdc++ ] localestub
: Devices.rdef
;