diff options
author | reillyg <reillyg@chromium.org> | 2016-01-29 17:06:41 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-30 01:08:08 +0000 |
commit | 7446a70a6b099681ea1b7f8ac03120b8c30d3e97 (patch) | |
tree | 0d854cfa64e92879ef05ac685fd3c9048ab7a799 /device/usb/usb_descriptors.cc | |
parent | b48cea969c402ff1650c9d4dde1ad7bd34288002 (diff) | |
download | chromium_src-7446a70a6b099681ea1b7f8ac03120b8c30d3e97.zip chromium_src-7446a70a6b099681ea1b7f8ac03120b8c30d3e97.tar.gz chromium_src-7446a70a6b099681ea1b7f8ac03120b8c30d3e97.tar.bz2 |
Move USB string descriptor reading out of usb_service_impl.cc.
As I did for WebUSB descriptor reading this allows this process to be
unit tested with a MockUsbDeviceHandle.
BUG=None
Review URL: https://codereview.chromium.org/1651603002
Cr-Commit-Position: refs/heads/master@{#372500}
Diffstat (limited to 'device/usb/usb_descriptors.cc')
-rw-r--r-- | device/usb/usb_descriptors.cc | 106 |
1 files changed, 96 insertions, 10 deletions
diff --git a/device/usb/usb_descriptors.cc b/device/usb/usb_descriptors.cc index a7f8ad4..840eb5d 100644 --- a/device/usb/usb_descriptors.cc +++ b/device/usb/usb_descriptors.cc @@ -8,12 +8,84 @@ #include <algorithm> +#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<uint8_t, base::string16>; +using IndexMapPtr = scoped_ptr<IndexMap>; + +// 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<void(const base::string16&)>& callback, + UsbTransferStatus status, + scoped_refptr<net::IOBuffer> buffer, + size_t length) { + base::string16 string; + if (status == USB_TRANSFER_COMPLETED && + ParseUsbStringDescriptor( + std::vector<uint8_t>(buffer->data(), buffer->data() + length), + &string)) { + callback.Run(string); + } else { + callback.Run(base::string16()); + } +} + +void ReadStringDescriptor( + scoped_refptr<UsbDeviceHandle> device_handle, + uint8_t index, + uint16_t language_id, + const base::Callback<void(const base::string16&)>& callback) { + scoped_refptr<net::IOBufferWithSize> 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<UsbDeviceHandle> device_handle, + IndexMapPtr index_map, + const base::Callback<void(IndexMapPtr)>& 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<uint8_t, IndexMap::iterator> 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<int>(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() : address(0), direction(USB_DIRECTION_INBOUND), @@ -50,23 +122,37 @@ UsbConfigDescriptor::~UsbConfigDescriptor() { bool ParseUsbStringDescriptor(const std::vector<uint8_t>& descriptor, base::string16* output) { - if (descriptor.size() < 2 || descriptor[1] != kStringDescriptorType) { + 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) { + if (length < 2) return false; - } else if (length == 2) { - // Special case to avoid indexing beyond the end of |descriptor|. - *output = base::string16(); - } else { - *output = base::string16( - reinterpret_cast<const base::char16*>(&descriptor[2]), length / 2 - 1); - } + + // The string is returned by the device in UTF-16LE. + *output = base::string16( + reinterpret_cast<const base::char16*>(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<UsbDeviceHandle> device_handle, + IndexMapPtr index_map, + const base::Callback<void(IndexMapPtr)>& 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 |