From e299a1d098598f3884da7a5358be6ceab86d651c Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 30 Jun 2025 10:28:21 +0200 Subject: [PATCH] feat: support complete WebUSB device properties (#47459) * feat: support complete WebUSB device properties * docs: correct type consistency --- docs/api/structures/usb-device.md | 40 ++++++++--- shell/browser/usb/usb_chooser_context.cc | 92 ++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 11 deletions(-) diff --git a/docs/api/structures/usb-device.md b/docs/api/structures/usb-device.md index e1f427fb4e..38a39c2885 100644 --- a/docs/api/structures/usb-device.md +++ b/docs/api/structures/usb-device.md @@ -1,17 +1,35 @@ # USBDevice Object +* `configuration` Object (optional) - A [USBConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/USBConfiguration) object containing information about the currently selected configuration of a USB device. + * `configurationValue` Integer - the configuration value of this configuration. + * `configurationName` string - the name provided by the device to describe this configuration. + * `interfaces` Object[] - An array of [USBInterface](https://developer.mozilla.org/en-US/docs/Web/API/USBInterface) objects containing information about an interface provided by the USB device. + * `interfaceNumber` Integer - the interface number of this interface. + * `alternate` Object - the currently selected alternative configuration of this interface. + * `alternateSetting` Integer - the alternate setting number of this interface. + * `interfaceClass` Integer - the class of this interface. See [USB.org](https://www.usb.org/defined-class-codes) for class code descriptions. + * `interfaceSubclass` Integer - the subclass of this interface. + * `interfaceProtocol` Integer - the protocol supported by this interface. + * `interfaceName` string (optional) - the name of the interface, if one is provided by the device. + * `endpoints` Object[] - an array containing instances of the [USBEndpoint interface](https://developer.mozilla.org/en-US/docs/Web/API/USBEndpoint) describing each of the endpoints that are part of this interface. + * `endpointNumber` Integer - this endpoint's "endpoint number" which is a value from 1 to 15. + * `direction` string - the direction in which this endpoint transfers data - can be either 'in' or 'out'. + * `type` string - the type of this endpoint - can be either 'bulk', 'interrupt', or 'isochronous'. + * `packetSize` Integer - the size of the packets that data sent through this endpoint will be divided into. + * `alternates` Object[] - an array containing instances of the [USBAlternateInterface](https://developer.mozilla.org/en-US/docs/Web/API/USBAlternateInterface) interface describing each of the alternative configurations possible for this interface. +* `configurations` Object[] - An array of [USBConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/USBConfiguration) interfaces for controlling a paired USB device. +* `deviceClass` Integer - The device class for the communication interface supported by the device. * `deviceId` string - Unique identifier for the device. -* `vendorId` Integer - The USB vendor ID. -* `productId` Integer - The USB product ID. -* `productName` string (optional) - Name of the device. -* `serialNumber` string (optional) - The USB device serial number. -* `manufacturerName` string (optional) - The manufacturer name of the device. -* `usbVersionMajor` Integer - The USB protocol major version supported by the device -* `usbVersionMinor` Integer - The USB protocol minor version supported by the device -* `usbVersionSubminor` Integer - The USB protocol subminor version supported by the device -* `deviceClass` Integer - The device class for the communication interface supported by the device -* `deviceSubclass` Integer - The device subclass for the communication interface supported by the device -* `deviceProtocol` Integer - The device protocol for the communication interface supported by the device +* `deviceProtocol` Integer - The device protocol for the communication interface supported by the device. +* `deviceSubclass` Integer - The device subclass for the communication interface supported by the device. * `deviceVersionMajor` Integer - The major version number of the device as defined by the device manufacturer. * `deviceVersionMinor` Integer - The minor version number of the device as defined by the device manufacturer. * `deviceVersionSubminor` Integer - The subminor version number of the device as defined by the device manufacturer. +* `manufacturerName` string (optional) - The manufacturer name of the device. +* `productId` Integer - The USB product ID. +* `productName` string (optional) - Name of the device. +* `serialNumber` string (optional) - The USB device serial number. +* `usbVersionMajor` Integer - The USB protocol major version supported by the device. +* `usbVersionMinor` Integer - The USB protocol minor version supported by the device. +* `usbVersionSubminor` Integer - The USB protocol subminor version supported by the device. +* `vendorId` Integer - The USB vendor ID. diff --git a/shell/browser/usb/usb_chooser_context.cc b/shell/browser/usb/usb_chooser_context.cc index d807e916f2..1e4b76d803 100644 --- a/shell/browser/usb/usb_chooser_context.cc +++ b/shell/browser/usb/usb_chooser_context.cc @@ -98,6 +98,98 @@ base::Value UsbChooserContext::DeviceInfoToValue( device_value.Set("deviceVersionMinor", device_info.device_version_minor); device_value.Set("deviceVersionSubminor", device_info.device_version_subminor); + + bool has_active_configuration = false; + base::Value::List configuration_list; + for (const auto& configuration : device_info.configurations) { + base::Value::Dict configuration_value; + configuration_value.Set("configurationValue", + configuration->configuration_value); + configuration_value.Set("configurationName", + configuration->configuration_name + ? *configuration->configuration_name + : std::u16string_view()); + + for (const auto& interface : configuration->interfaces) { + base::Value::Dict interface_value; + interface_value.Set("interfaceNumber", interface->interface_number); + + base::Value::List alternate_list; + for (const auto& alternate : interface->alternates) { + base::Value::Dict alternate_value; + alternate_value.Set("alternateSetting", alternate->alternate_setting); + alternate_value.Set("interfaceClass", alternate->class_code); + alternate_value.Set("interfaceSubclass", alternate->subclass_code); + alternate_value.Set("interfaceProtocol", alternate->protocol_code); + alternate_value.Set("interfaceName", alternate->interface_name + ? *alternate->interface_name + : std::u16string_view()); + + base::Value::List endpoint_list; + for (const auto& endpoint : alternate->endpoints) { + base::Value::Dict endpoint_value; + endpoint_value.Set("endpointNumber", endpoint->endpoint_number); + + bool inbound = endpoint->direction == + device::mojom::UsbTransferDirection::INBOUND; + endpoint_value.Set("direction", inbound ? "in" : "out"); + + std::string type; + switch (endpoint->type) { + case device::mojom::UsbTransferType::ISOCHRONOUS: + type = "isochronous"; + break; + case device::mojom::UsbTransferType::BULK: + type = "bulk"; + break; + case device::mojom::UsbTransferType::INTERRUPT: + type = "interrupt"; + break; + default: + NOTREACHED() << "Unknown USB transfer type: " + << static_cast(endpoint->type); + } + endpoint_value.Set("type", type); + endpoint_value.Set("packetSize", + static_cast(endpoint->packet_size)); + endpoint_list.Append(std::move(endpoint_value)); + } + + alternate_value.Set("endpoints", base::Value(std::move(endpoint_list))); + + if (alternate->alternate_setting == 0) { + auto active_alternate_value = alternate_value.Clone(); + interface_value.Set("alternate", std::move(active_alternate_value)); + } + + alternate_list.Append(std::move(alternate_value)); + } + + interface_value.Set("alternates", std::move(alternate_list)); + + configuration_value.Set("interfaces", + base::Value(std::move(interface_value))); + } + + if (device_info.active_configuration && + device_info.active_configuration == + configuration->configuration_value) { + auto active_configuration_value = configuration_value.Clone(); + has_active_configuration = true; + configuration_value.Set("configuration", + std::move(active_configuration_value)); + } + + configuration_list.Append(std::move(configuration_value)); + } + + device_value.Set("configurations", std::move(configuration_list)); + + // Set value for "configuration" to null if no active configuration. + if (!has_active_configuration) { + device_value.Set("configuration", base::Value()); + } + return base::Value(std::move(device_value)); }