// 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 "device/usb/usb_descriptors.h" #include #include #include "base/barrier_closure.h" #include "base/bind.h" #include "device/usb/usb_device_handle.h" #include "net/base/io_buffer.h" namespace device { namespace { using IndexMap = std::map; using IndexMapPtr = scoped_ptr; // Standard USB requests and descriptor types: const uint8_t kGetDescriptorRequest = 0x06; const uint8_t kStringDescriptorType = 0x03; const int kControlTransferTimeout = 60000; // 1 minute void StoreStringDescriptor(IndexMap::iterator it, const base::Closure& callback, const base::string16& string) { it->second = string; callback.Run(); } void OnReadStringDescriptor( const base::Callback& callback, UsbTransferStatus status, scoped_refptr buffer, size_t length) { base::string16 string; if (status == USB_TRANSFER_COMPLETED && ParseUsbStringDescriptor( std::vector(buffer->data(), buffer->data() + length), &string)) { callback.Run(string); } else { callback.Run(base::string16()); } } void ReadStringDescriptor( scoped_refptr device_handle, uint8_t index, uint16_t language_id, const base::Callback& callback) { scoped_refptr buffer = new net::IOBufferWithSize(255); device_handle->ControlTransfer( USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE, kGetDescriptorRequest, kStringDescriptorType << 8 | index, language_id, buffer, buffer->size(), kControlTransferTimeout, base::Bind(&OnReadStringDescriptor, callback)); } void OnReadLanguageIds(scoped_refptr device_handle, IndexMapPtr index_map, const base::Callback& callback, const base::string16& 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 iterator_map; for (auto it = index_map->begin(); it != index_map->end(); ++it) iterator_map[it->first] = it; base::Closure barrier = base::BarrierClosure(static_cast(iterator_map.size()), base::Bind(callback, base::Passed(&index_map))); for (const auto& map_entry : iterator_map) { ReadStringDescriptor( device_handle, map_entry.first, language_id, base::Bind(&StoreStringDescriptor, map_entry.second, barrier)); } } } // namespace UsbEndpointDescriptor::UsbEndpointDescriptor( uint8_t address, UsbEndpointDirection direction, uint16_t maximum_packet_size, UsbSynchronizationType synchronization_type, UsbTransferType transfer_type, UsbUsageType usage_type, uint16_t polling_interval) : address(address), direction(direction), maximum_packet_size(maximum_packet_size), synchronization_type(synchronization_type), transfer_type(transfer_type), usage_type(usage_type), polling_interval(polling_interval) {} UsbEndpointDescriptor::~UsbEndpointDescriptor() = default; UsbInterfaceDescriptor::UsbInterfaceDescriptor(uint8_t interface_number, uint8_t alternate_setting, uint8_t interface_class, uint8_t interface_subclass, uint8_t interface_protocol) : interface_number(interface_number), alternate_setting(alternate_setting), interface_class(interface_class), interface_subclass(interface_subclass), interface_protocol(interface_protocol) {} UsbInterfaceDescriptor::~UsbInterfaceDescriptor() = default; UsbConfigDescriptor::UsbConfigDescriptor(uint8_t configuration_value, bool self_powered, bool remote_wakeup, uint16_t maximum_power) : configuration_value(configuration_value), self_powered(self_powered), remote_wakeup(remote_wakeup), maximum_power(maximum_power) {} UsbConfigDescriptor::~UsbConfigDescriptor() = default; bool ParseUsbStringDescriptor(const std::vector& descriptor, base::string16* 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 = base::string16( reinterpret_cast(descriptor.data() + 2), length / 2 - 1); 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 device_handle, IndexMapPtr index_map, const base::Callback& callback) { if (index_map->empty()) { callback.Run(std::move(index_map)); return; } ReadStringDescriptor(device_handle, 0, 0, base::Bind(&OnReadLanguageIds, device_handle, base::Passed(&index_map), callback)); } } // namespace device