123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/device/usb/usb_descriptors.h"
- #include <stddef.h>
- #include <algorithm>
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/barrier_closure.h"
- #include "base/bind.h"
- #include "base/memory/ref_counted_memory.h"
- #include "services/device/public/cpp/usb/usb_utils.h"
- #include "services/device/usb/usb_device_handle.h"
- namespace device {
- using mojom::UsbAlternateInterfaceInfoPtr;
- using mojom::UsbConfigurationInfoPtr;
- using mojom::UsbControlTransferRecipient;
- using mojom::UsbControlTransferType;
- using mojom::UsbDeviceInfoPtr;
- using mojom::UsbEndpointInfoPtr;
- using mojom::UsbInterfaceInfoPtr;
- using mojom::UsbSynchronizationType;
- using mojom::UsbTransferDirection;
- using mojom::UsbTransferStatus;
- using mojom::UsbTransferType;
- using mojom::UsbUsageType;
- namespace {
- using IndexMap = std::map<uint8_t, std::u16string>;
- using IndexMapPtr = std::unique_ptr<IndexMap>;
- // Standard USB requests and descriptor types:
- const uint8_t kGetDescriptorRequest = 0x06;
- const uint8_t kDeviceDescriptorType = 0x01;
- const uint8_t kConfigurationDescriptorType = 0x02;
- const uint8_t kStringDescriptorType = 0x03;
- const uint8_t kInterfaceDescriptorType = 0x04;
- const uint8_t kEndpointDescriptorType = 0x05;
- const uint8_t kInterfaceAssociationDescriptorType = 11;
- const uint8_t kDeviceDescriptorLength = 18;
- const uint8_t kConfigurationDescriptorLength = 9;
- const uint8_t kInterfaceDescriptorLength = 9;
- const uint8_t kEndpointDescriptorLength = 7;
- const uint8_t kInterfaceAssociationDescriptorLength = 8;
- const int kControlTransferTimeoutMs = 2000; // 2 seconds
- struct UsbInterfaceAssociationDescriptor {
- UsbInterfaceAssociationDescriptor(uint8_t first_interface,
- uint8_t interface_count)
- : first_interface(first_interface), interface_count(interface_count) {}
- bool operator<(const UsbInterfaceAssociationDescriptor& other) const {
- return first_interface < other.first_interface;
- }
- uint8_t first_interface;
- uint8_t interface_count;
- };
- void ParseInterfaceAssociationDescriptors(
- const std::vector<uint8_t>& buffer,
- std::vector<UsbInterfaceAssociationDescriptor>* functions) {
- auto it = buffer.begin();
- while (it != buffer.end()) {
- // All descriptors must be at least 2 byte which means the length and type
- // are safe to read.
- if (std::distance(it, buffer.end()) < 2)
- return;
- uint8_t length = it[0];
- if (length > std::distance(it, buffer.end()))
- return;
- if (it[1] == kInterfaceAssociationDescriptorType &&
- length == kInterfaceAssociationDescriptorLength) {
- functions->push_back(UsbInterfaceAssociationDescriptor(it[2], it[3]));
- }
- std::advance(it, length);
- }
- }
- void OnDoneReadingConfigDescriptors(
- scoped_refptr<UsbDeviceHandle> device_handle,
- std::unique_ptr<UsbDeviceDescriptor> desc,
- base::OnceCallback<void(std::unique_ptr<UsbDeviceDescriptor>)> callback) {
- if (desc->num_configurations == desc->device_info->configurations.size()) {
- std::move(callback).Run(std::move(desc));
- } else {
- LOG(ERROR) << "Failed to read all configuration descriptors. Expected "
- << static_cast<int>(desc->num_configurations) << ", got "
- << desc->device_info->configurations.size() << ".";
- std::move(callback).Run(nullptr);
- }
- }
- void OnReadConfigDescriptor(UsbDeviceDescriptor* desc,
- base::OnceClosure closure,
- UsbTransferStatus status,
- scoped_refptr<base::RefCountedBytes> buffer,
- size_t length) {
- if (status == UsbTransferStatus::COMPLETED) {
- if (!desc->Parse(base::make_span(buffer->front(), length))) {
- LOG(ERROR) << "Failed to parse configuration descriptor.";
- }
- } else {
- LOG(ERROR) << "Failed to read configuration descriptor.";
- }
- std::move(closure).Run();
- }
- void OnReadConfigDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
- UsbDeviceDescriptor* desc,
- uint8_t index,
- base::OnceClosure closure,
- UsbTransferStatus status,
- scoped_refptr<base::RefCountedBytes> header,
- size_t length) {
- if (status == UsbTransferStatus::COMPLETED &&
- length == kConfigurationDescriptorLength) {
- const uint8_t* data = header->front();
- uint16_t total_length = data[2] | data[3] << 8;
- auto buffer = base::MakeRefCounted<base::RefCountedBytes>(total_length);
- device_handle->ControlTransfer(
- UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
- UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
- kConfigurationDescriptorType << 8 | index, 0, buffer,
- kControlTransferTimeoutMs,
- base::BindOnce(&OnReadConfigDescriptor, desc, std::move(closure)));
- } else {
- LOG(ERROR) << "Failed to read length for configuration "
- << static_cast<int>(index) << ".";
- std::move(closure).Run();
- }
- }
- void OnReadDeviceDescriptor(
- scoped_refptr<UsbDeviceHandle> device_handle,
- base::OnceCallback<void(std::unique_ptr<UsbDeviceDescriptor>)> callback,
- UsbTransferStatus status,
- scoped_refptr<base::RefCountedBytes> buffer,
- size_t length) {
- if (status != UsbTransferStatus::COMPLETED) {
- LOG(ERROR) << "Failed to read device descriptor.";
- std::move(callback).Run(nullptr);
- return;
- }
- std::unique_ptr<UsbDeviceDescriptor> desc(new UsbDeviceDescriptor());
- if (!desc->Parse(base::make_span(buffer->front(), length))) {
- LOG(ERROR) << "Device descriptor parsing error.";
- std::move(callback).Run(nullptr);
- return;
- }
- if (desc->num_configurations == 0) {
- std::move(callback).Run(std::move(desc));
- return;
- }
- uint8_t num_configurations = desc->num_configurations;
- UsbDeviceDescriptor* desc_ptr = desc.get();
- base::RepeatingClosure closure = base::BarrierClosure(
- num_configurations,
- base::BindOnce(OnDoneReadingConfigDescriptors, device_handle,
- std::move(desc), std::move(callback)));
- for (uint8_t i = 0; i < num_configurations; ++i) {
- auto header = base::MakeRefCounted<base::RefCountedBytes>(
- kConfigurationDescriptorLength);
- device_handle->ControlTransfer(
- UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
- UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
- kConfigurationDescriptorType << 8 | i, 0, header,
- kControlTransferTimeoutMs,
- base::BindOnce(&OnReadConfigDescriptorHeader, device_handle, desc_ptr,
- i, closure));
- }
- }
- void StoreStringDescriptor(IndexMap::iterator it,
- base::OnceClosure callback,
- const std::u16string& string) {
- it->second = string;
- std::move(callback).Run();
- }
- void OnReadStringDescriptor(
- base::OnceCallback<void(const std::u16string&)> callback,
- UsbTransferStatus status,
- scoped_refptr<base::RefCountedBytes> buffer,
- size_t length) {
- std::u16string string;
- if (status == UsbTransferStatus::COMPLETED &&
- ParseUsbStringDescriptor(
- std::vector<uint8_t>(buffer->front(), buffer->front() + length),
- &string)) {
- std::move(callback).Run(string);
- } else {
- std::move(callback).Run(std::u16string());
- }
- }
- void ReadStringDescriptor(
- scoped_refptr<UsbDeviceHandle> device_handle,
- uint8_t index,
- uint16_t language_id,
- base::OnceCallback<void(const std::u16string&)> callback) {
- auto buffer = base::MakeRefCounted<base::RefCountedBytes>(255);
- device_handle->ControlTransfer(
- UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
- UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
- kStringDescriptorType << 8 | index, language_id, buffer,
- kControlTransferTimeoutMs,
- base::BindOnce(&OnReadStringDescriptor, std::move(callback)));
- }
- void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
- IndexMapPtr index_map,
- base::OnceCallback<void(IndexMapPtr)> callback,
- const std::u16string& languages) {
- // Default to English unless the device provides a language and then just pick
- // the first one.
- uint16_t language_id = languages.empty() ? 0x0409 : languages[0];
- std::map<uint8_t, IndexMap::iterator> iterator_map;
- for (auto it = index_map->begin(); it != index_map->end(); ++it)
- iterator_map[it->first] = it;
- base::RepeatingClosure barrier = base::BarrierClosure(
- static_cast<int>(iterator_map.size()),
- base::BindOnce(std::move(callback), std::move(index_map)));
- for (const auto& map_entry : iterator_map) {
- ReadStringDescriptor(
- device_handle, map_entry.first, language_id,
- base::BindOnce(&StoreStringDescriptor, map_entry.second, barrier));
- }
- }
- } // namespace
- CombinedInterfaceInfo::CombinedInterfaceInfo(
- const mojom::UsbInterfaceInfo* interface,
- const mojom::UsbAlternateInterfaceInfo* alternate)
- : interface(interface), alternate(alternate) {}
- bool CombinedInterfaceInfo::IsValid() const {
- return interface && alternate;
- }
- UsbDeviceDescriptor::UsbDeviceDescriptor()
- : device_info(mojom::UsbDeviceInfo::New()) {}
- UsbDeviceDescriptor::~UsbDeviceDescriptor() = default;
- bool UsbDeviceDescriptor::Parse(base::span<const uint8_t> buffer) {
- mojom::UsbConfigurationInfo* last_config = nullptr;
- mojom::UsbInterfaceInfo* last_interface = nullptr;
- mojom::UsbEndpointInfo* last_endpoint = nullptr;
- for (auto it = buffer.begin(); it != buffer.end();
- /* incremented internally */) {
- const uint8_t* data = &it[0];
- uint8_t length = data[0];
- if (length < 2 || length > std::distance(it, buffer.end()))
- return false;
- it += length;
- switch (data[1] /* bDescriptorType */) {
- case kDeviceDescriptorType:
- if (device_info->configurations.size() > 0 ||
- length < kDeviceDescriptorLength) {
- return false;
- }
- device_info->usb_version_minor = data[2] >> 4 & 0xf;
- device_info->usb_version_subminor = data[2] & 0xf;
- device_info->usb_version_major = data[3];
- device_info->class_code = data[4];
- device_info->subclass_code = data[5];
- device_info->protocol_code = data[6];
- device_info->vendor_id = data[8] | data[9] << 8;
- device_info->product_id = data[10] | data[11] << 8;
- device_info->device_version_minor = data[12] >> 4 & 0xf;
- device_info->device_version_subminor = data[12] & 0xf;
- device_info->device_version_major = data[13];
- i_manufacturer = data[14];
- i_product = data[15];
- i_serial_number = data[16];
- num_configurations = data[17];
- break;
- case kConfigurationDescriptorType:
- if (length < kConfigurationDescriptorLength)
- return false;
- if (last_config) {
- AssignFirstInterfaceNumbers(last_config);
- AggregateInterfacesForConfig(last_config);
- }
- device_info->configurations.push_back(
- BuildUsbConfigurationInfoPtr(data));
- last_config = device_info->configurations.back().get();
- last_interface = nullptr;
- last_endpoint = nullptr;
- break;
- case kInterfaceDescriptorType:
- if (!last_config || length < kInterfaceDescriptorLength)
- return false;
- last_config->interfaces.push_back(BuildUsbInterfaceInfoPtr(data));
- last_interface = last_config->interfaces.back().get();
- last_endpoint = nullptr;
- break;
- case kEndpointDescriptorType:
- if (!last_interface || length < kEndpointDescriptorLength)
- return false;
- last_interface->alternates[0]->endpoints.push_back(
- BuildUsbEndpointInfoPtr(data));
- last_endpoint = last_interface->alternates[0]->endpoints.back().get();
- break;
- default:
- // Append unknown descriptor types to the |extra_data| field of the last
- // descriptor.
- if (last_endpoint) {
- last_endpoint->extra_data.insert(last_endpoint->extra_data.end(),
- data, data + length);
- } else if (last_interface) {
- DCHECK_EQ(1u, last_interface->alternates.size());
- last_interface->alternates[0]->extra_data.insert(
- last_interface->alternates[0]->extra_data.end(), data,
- data + length);
- } else if (last_config) {
- last_config->extra_data.insert(last_config->extra_data.end(), data,
- data + length);
- }
- }
- }
- if (last_config) {
- AssignFirstInterfaceNumbers(last_config);
- AggregateInterfacesForConfig(last_config);
- }
- return true;
- }
- void ReadUsbDescriptors(
- scoped_refptr<UsbDeviceHandle> device_handle,
- base::OnceCallback<void(std::unique_ptr<UsbDeviceDescriptor>)> callback) {
- auto buffer =
- base::MakeRefCounted<base::RefCountedBytes>(kDeviceDescriptorLength);
- device_handle->ControlTransfer(
- UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
- UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
- kDeviceDescriptorType << 8, 0, buffer, kControlTransferTimeoutMs,
- base::BindOnce(&OnReadDeviceDescriptor, device_handle,
- std::move(callback)));
- }
- bool ParseUsbStringDescriptor(const std::vector<uint8_t>& descriptor,
- std::u16string* output) {
- if (descriptor.size() < 2 || descriptor[1] != kStringDescriptorType)
- return false;
- // Let the device return a buffer larger than the actual string but prefer the
- // length reported inside the descriptor.
- size_t length = descriptor[0];
- length = std::min(length, descriptor.size());
- if (length < 2)
- return false;
- // The string is returned by the device in UTF-16LE.
- *output =
- std::u16string(reinterpret_cast<const char16_t*>(descriptor.data() + 2),
- (length - 2) / sizeof(char16_t));
- return true;
- }
- // For each key in |index_map| this function reads that string descriptor from
- // |device_handle| and updates the value in in |index_map|.
- void ReadUsbStringDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
- IndexMapPtr index_map,
- base::OnceCallback<void(IndexMapPtr)> callback) {
- if (index_map->empty()) {
- std::move(callback).Run(std::move(index_map));
- return;
- }
- ReadStringDescriptor(
- device_handle, 0, 0,
- base::BindOnce(&OnReadLanguageIds, device_handle, std::move(index_map),
- std::move(callback)));
- }
- UsbEndpointInfoPtr BuildUsbEndpointInfoPtr(const uint8_t* data) {
- DCHECK_GE(data[0], kEndpointDescriptorLength);
- DCHECK_EQ(data[1], kEndpointDescriptorType);
- return BuildUsbEndpointInfoPtr(
- data[2] /* bEndpointAddress */, data[3] /* bmAttributes */,
- data[4] + (data[5] << 8) /* wMaxPacketSize */, data[6] /* bInterval */);
- }
- UsbEndpointInfoPtr BuildUsbEndpointInfoPtr(uint8_t address,
- uint8_t attributes,
- uint16_t maximum_packet_size,
- uint8_t polling_interval) {
- UsbEndpointInfoPtr endpoint = mojom::UsbEndpointInfo::New();
- endpoint->endpoint_number = ConvertEndpointAddressToNumber(address);
- // These fields are defined in Table 9-24 of the USB 3.1 Specification.
- switch (address & 0x80) {
- case 0x00:
- endpoint->direction = UsbTransferDirection::OUTBOUND;
- break;
- case 0x80:
- endpoint->direction = UsbTransferDirection::INBOUND;
- break;
- }
- switch (attributes & 0x03) {
- case 0x00:
- endpoint->type = UsbTransferType::CONTROL;
- break;
- case 0x01:
- endpoint->type = UsbTransferType::ISOCHRONOUS;
- break;
- case 0x02:
- endpoint->type = UsbTransferType::BULK;
- break;
- case 0x03:
- endpoint->type = UsbTransferType::INTERRUPT;
- break;
- }
- switch (attributes & 0x0F) {
- // Isochronous endpoints only.
- case 0x05:
- endpoint->synchronization_type = UsbSynchronizationType::ASYNCHRONOUS;
- break;
- case 0x09:
- endpoint->synchronization_type = UsbSynchronizationType::ADAPTIVE;
- break;
- case 0x0D:
- endpoint->synchronization_type = UsbSynchronizationType::SYNCHRONOUS;
- break;
- default:
- endpoint->synchronization_type = UsbSynchronizationType::NONE;
- }
- switch (attributes & 0x33) {
- // Isochronous endpoint usages.
- case 0x01:
- endpoint->usage_type = UsbUsageType::DATA;
- break;
- case 0x11:
- endpoint->usage_type = UsbUsageType::FEEDBACK;
- break;
- case 0x21:
- endpoint->usage_type = UsbUsageType::EXPLICIT_FEEDBACK;
- break;
- // Interrupt endpoint usages.
- case 0x03:
- endpoint->usage_type = UsbUsageType::PERIODIC;
- break;
- case 0x13:
- endpoint->usage_type = UsbUsageType::NOTIFICATION;
- break;
- default:
- endpoint->usage_type = UsbUsageType::RESERVED;
- }
- endpoint->packet_size = static_cast<uint32_t>(maximum_packet_size);
- endpoint->polling_interval = polling_interval;
- return endpoint;
- }
- UsbInterfaceInfoPtr BuildUsbInterfaceInfoPtr(const uint8_t* data) {
- DCHECK_GE(data[0], kInterfaceDescriptorLength);
- DCHECK_EQ(data[1], kInterfaceDescriptorType);
- return BuildUsbInterfaceInfoPtr(
- data[2] /* bInterfaceNumber */, data[3] /* bAlternateSetting */,
- data[5] /* bInterfaceClass */, data[6] /* bInterfaceSubClass */,
- data[7] /* bInterfaceProtocol */);
- }
- UsbInterfaceInfoPtr BuildUsbInterfaceInfoPtr(uint8_t interface_number,
- uint8_t alternate_setting,
- uint8_t interface_class,
- uint8_t interface_subclass,
- uint8_t interface_protocol) {
- UsbInterfaceInfoPtr interface_info = mojom::UsbInterfaceInfo::New();
- interface_info->interface_number = interface_number;
- interface_info->first_interface = interface_number;
- UsbAlternateInterfaceInfoPtr alternate =
- mojom::UsbAlternateInterfaceInfo::New();
- alternate->alternate_setting = alternate_setting;
- alternate->class_code = interface_class;
- alternate->subclass_code = interface_subclass;
- alternate->protocol_code = interface_protocol;
- interface_info->alternates.push_back(std::move(alternate));
- return interface_info;
- }
- // Aggregate each alternate setting into an InterfaceInfo corresponding to its
- // interface number.
- void AggregateInterfacesForConfig(mojom::UsbConfigurationInfo* config) {
- std::map<uint8_t, device::mojom::UsbInterfaceInfo*> interface_map;
- std::vector<device::mojom::UsbInterfaceInfoPtr> interfaces =
- std::move(config->interfaces);
- config->interfaces.clear();
- for (size_t i = 0; i < interfaces.size(); ++i) {
- // As interfaces should appear in order, this map could be unnecessary,
- // but this errs on the side of caution.
- auto iter = interface_map.find(interfaces[i]->interface_number);
- if (iter == interface_map.end()) {
- // This is the first time we're seeing an alternate with this interface
- // number, so add a new InterfaceInfo to the array and map the number.
- config->interfaces.push_back(std::move(interfaces[i]));
- interface_map.insert(
- std::make_pair(config->interfaces.back()->interface_number,
- config->interfaces.back().get()));
- } else {
- DCHECK_EQ(1u, interfaces[i]->alternates.size());
- iter->second->alternates.push_back(
- std::move(interfaces[i]->alternates[0]));
- }
- }
- }
- CombinedInterfaceInfo FindInterfaceInfoFromConfig(
- const mojom::UsbConfigurationInfo* config,
- uint8_t interface_number,
- uint8_t alternate_setting) {
- CombinedInterfaceInfo interface_info;
- if (!config) {
- return interface_info;
- }
- for (const auto& iface : config->interfaces) {
- if (iface->interface_number == interface_number) {
- interface_info.interface = iface.get();
- for (const auto& alternate : iface->alternates) {
- if (alternate->alternate_setting == alternate_setting) {
- interface_info.alternate = alternate.get();
- break;
- }
- }
- }
- }
- return interface_info;
- }
- UsbConfigurationInfoPtr BuildUsbConfigurationInfoPtr(const uint8_t* data) {
- DCHECK_GE(data[0], kConfigurationDescriptorLength);
- DCHECK_EQ(data[1], kConfigurationDescriptorType);
- return BuildUsbConfigurationInfoPtr(data[5] /* bConfigurationValue */,
- (data[7] & 0x02) != 0 /* bmAttributes */,
- (data[7] & 0x04) != 0 /* bmAttributes */,
- data[8] /* bMaxPower */);
- }
- UsbConfigurationInfoPtr BuildUsbConfigurationInfoPtr(
- uint8_t configuration_value,
- bool self_powered,
- bool remote_wakeup,
- uint8_t maximum_power) {
- UsbConfigurationInfoPtr config = mojom::UsbConfigurationInfo::New();
- config->configuration_value = configuration_value;
- config->self_powered = self_powered;
- config->remote_wakeup = remote_wakeup;
- config->maximum_power = maximum_power;
- return config;
- }
- void AssignFirstInterfaceNumbers(mojom::UsbConfigurationInfo* config) {
- std::vector<UsbInterfaceAssociationDescriptor> functions;
- ParseInterfaceAssociationDescriptors(config->extra_data, &functions);
- for (const auto& interface : config->interfaces) {
- DCHECK_EQ(1u, interface->alternates.size());
- ParseInterfaceAssociationDescriptors(interface->alternates[0]->extra_data,
- &functions);
- for (auto& endpoint : interface->alternates[0]->endpoints)
- ParseInterfaceAssociationDescriptors(endpoint->extra_data, &functions);
- }
- // libusb has collected interface association descriptors in the |extra_data|
- // fields of other descriptor types. This may have disturbed their order
- // but sorting by the bFirstInterface should fix it.
- std::sort(functions.begin(), functions.end());
- uint8_t remaining_interfaces = 0;
- auto function_it = functions.cbegin();
- auto interface_it = config->interfaces.begin();
- while (interface_it != config->interfaces.end()) {
- if (remaining_interfaces > 0) {
- // Continuation of a previous function. Tag all alternate interfaces
- // (which are guaranteed to be contiguous).
- for (uint8_t interface_number = (*interface_it)->interface_number;
- interface_it != config->interfaces.end() &&
- (*interface_it)->interface_number == interface_number;
- ++interface_it) {
- (*interface_it)->first_interface = function_it->first_interface;
- }
- if (--remaining_interfaces == 0)
- ++function_it;
- } else if (function_it != functions.end() &&
- (*interface_it)->interface_number ==
- function_it->first_interface) {
- // Start of a new function.
- (*interface_it)->first_interface = function_it->first_interface;
- if (function_it->interface_count > 1)
- remaining_interfaces = function_it->interface_count - 1;
- else
- ++function_it;
- ++interface_it;
- } else {
- // Unassociated interfaces already have |first_interface| set to
- // |interface_number|.
- ++interface_it;
- }
- }
- }
- } // namespace device
|