Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / device / usb / usb_device_impl.cc
blobb3abe74aebb1e0beeea35c17e62c832f9a2fe726
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/usb/usb_device_impl.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "components/device_event_log/device_event_log.h"
16 #include "device/usb/usb_context.h"
17 #include "device/usb/usb_descriptors.h"
18 #include "device/usb/usb_device_handle_impl.h"
19 #include "device/usb/usb_error.h"
20 #include "third_party/libusb/src/libusb/libusb.h"
22 #if defined(OS_CHROMEOS)
23 #include "chromeos/dbus/dbus_thread_manager.h"
24 #include "chromeos/dbus/permission_broker_client.h"
25 #include "dbus/file_descriptor.h"
26 #endif // defined(OS_CHROMEOS)
28 namespace device {
30 namespace {
32 UsbEndpointDirection GetDirection(
33 const libusb_endpoint_descriptor* descriptor) {
34 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
35 case LIBUSB_ENDPOINT_IN:
36 return USB_DIRECTION_INBOUND;
37 case LIBUSB_ENDPOINT_OUT:
38 return USB_DIRECTION_OUTBOUND;
39 default:
40 NOTREACHED();
41 return USB_DIRECTION_INBOUND;
45 UsbSynchronizationType GetSynchronizationType(
46 const libusb_endpoint_descriptor* descriptor) {
47 switch ((descriptor->bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2) {
48 case LIBUSB_ISO_SYNC_TYPE_NONE:
49 return USB_SYNCHRONIZATION_NONE;
50 case LIBUSB_ISO_SYNC_TYPE_ASYNC:
51 return USB_SYNCHRONIZATION_ASYNCHRONOUS;
52 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
53 return USB_SYNCHRONIZATION_ADAPTIVE;
54 case LIBUSB_ISO_SYNC_TYPE_SYNC:
55 return USB_SYNCHRONIZATION_SYNCHRONOUS;
56 default:
57 NOTREACHED();
58 return USB_SYNCHRONIZATION_NONE;
62 UsbTransferType GetTransferType(const libusb_endpoint_descriptor* descriptor) {
63 switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
64 case LIBUSB_TRANSFER_TYPE_CONTROL:
65 return USB_TRANSFER_CONTROL;
66 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
67 return USB_TRANSFER_ISOCHRONOUS;
68 case LIBUSB_TRANSFER_TYPE_BULK:
69 return USB_TRANSFER_BULK;
70 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
71 return USB_TRANSFER_INTERRUPT;
72 default:
73 NOTREACHED();
74 return USB_TRANSFER_CONTROL;
78 UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
79 switch ((descriptor->bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4) {
80 case LIBUSB_ISO_USAGE_TYPE_DATA:
81 return USB_USAGE_DATA;
82 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
83 return USB_USAGE_FEEDBACK;
84 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
85 return USB_USAGE_EXPLICIT_FEEDBACK;
86 default:
87 NOTREACHED();
88 return USB_USAGE_DATA;
92 void ConvertConfigDescriptor(const libusb_config_descriptor* platform_config,
93 UsbConfigDescriptor* configuration) {
94 configuration->configuration_value = platform_config->bConfigurationValue;
95 configuration->self_powered = (platform_config->bmAttributes & 0x40) != 0;
96 configuration->remote_wakeup = (platform_config->bmAttributes & 0x20) != 0;
97 configuration->maximum_power = platform_config->MaxPower * 2;
99 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
100 const struct libusb_interface* platform_interface =
101 &platform_config->interface[i];
102 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
103 const struct libusb_interface_descriptor* platform_alt_setting =
104 &platform_interface->altsetting[j];
105 UsbInterfaceDescriptor interface;
107 interface.interface_number = platform_alt_setting->bInterfaceNumber;
108 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
109 interface.interface_class = platform_alt_setting->bInterfaceClass;
110 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
111 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
113 interface.endpoints.reserve(platform_alt_setting->bNumEndpoints);
114 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
115 const struct libusb_endpoint_descriptor* platform_endpoint =
116 &platform_alt_setting->endpoint[k];
117 UsbEndpointDescriptor endpoint;
119 endpoint.address = platform_endpoint->bEndpointAddress;
120 endpoint.direction = GetDirection(platform_endpoint);
121 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
122 endpoint.synchronization_type =
123 GetSynchronizationType(platform_endpoint);
124 endpoint.transfer_type = GetTransferType(platform_endpoint);
125 endpoint.usage_type = GetUsageType(platform_endpoint);
126 endpoint.polling_interval = platform_endpoint->bInterval;
127 endpoint.extra_data = std::vector<uint8_t>(
128 platform_endpoint->extra,
129 platform_endpoint->extra + platform_endpoint->extra_length);
131 interface.endpoints.push_back(endpoint);
134 interface.extra_data = std::vector<uint8_t>(
135 platform_alt_setting->extra,
136 platform_alt_setting->extra + platform_alt_setting->extra_length);
138 configuration->interfaces.push_back(interface);
142 configuration->extra_data = std::vector<uint8_t>(
143 platform_config->extra,
144 platform_config->extra + platform_config->extra_length);
147 } // namespace
149 UsbDeviceImpl::UsbDeviceImpl(
150 scoped_refptr<UsbContext> context,
151 PlatformUsbDevice platform_device,
152 uint16 vendor_id,
153 uint16 product_id,
154 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
155 : UsbDevice(vendor_id,
156 product_id,
157 base::string16(),
158 base::string16(),
159 base::string16()),
160 platform_device_(platform_device),
161 context_(context),
162 task_runner_(base::ThreadTaskRunnerHandle::Get()),
163 blocking_task_runner_(blocking_task_runner) {
164 CHECK(platform_device) << "platform_device cannot be NULL";
165 libusb_ref_device(platform_device);
166 ReadAllConfigurations();
167 RefreshActiveConfiguration();
170 UsbDeviceImpl::~UsbDeviceImpl() {
171 // The destructor must be safe to call from any thread.
172 libusb_unref_device(platform_device_);
175 #if defined(OS_CHROMEOS)
177 void UsbDeviceImpl::CheckUsbAccess(const ResultCallback& callback) {
178 DCHECK(thread_checker_.CalledOnValidThread());
179 chromeos::PermissionBrokerClient* client =
180 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
181 DCHECK(client) << "Could not get permission broker client.";
182 client->CheckPathAccess(device_path_, callback);
185 #endif // defined(OS_CHROMEOS)
187 void UsbDeviceImpl::Open(const OpenCallback& callback) {
188 DCHECK(thread_checker_.CalledOnValidThread());
190 #if defined(OS_CHROMEOS)
191 chromeos::PermissionBrokerClient* client =
192 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
193 DCHECK(client) << "Could not get permission broker client.";
194 client->OpenPath(
195 device_path_,
196 base::Bind(&UsbDeviceImpl::OnOpenRequestComplete, this, callback));
197 #else
198 blocking_task_runner_->PostTask(
199 FROM_HERE,
200 base::Bind(&UsbDeviceImpl::OpenOnBlockingThread, this, callback));
201 #endif // defined(OS_CHROMEOS)
204 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
205 DCHECK(thread_checker_.CalledOnValidThread());
207 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
208 ++it) {
209 if (it->get() == handle.get()) {
210 (*it)->InternalClose();
211 handles_.erase(it);
212 return true;
215 return false;
218 const UsbConfigDescriptor* UsbDeviceImpl::GetActiveConfiguration() {
219 DCHECK(thread_checker_.CalledOnValidThread());
220 return active_configuration_;
223 void UsbDeviceImpl::OnDisconnect() {
224 DCHECK(thread_checker_.CalledOnValidThread());
226 // Swap the list of handles into a local variable because closing all open
227 // handles may release the last reference to this object.
228 HandlesVector handles;
229 swap(handles, handles_);
231 for (const scoped_refptr<UsbDeviceHandleImpl>& handle : handles_) {
232 handle->InternalClose();
236 void UsbDeviceImpl::ReadAllConfigurations() {
237 libusb_device_descriptor device_descriptor;
238 int rv = libusb_get_device_descriptor(platform_device_, &device_descriptor);
239 if (rv == LIBUSB_SUCCESS) {
240 uint8_t num_configurations = device_descriptor.bNumConfigurations;
241 configurations_.reserve(num_configurations);
242 for (uint8_t i = 0; i < num_configurations; ++i) {
243 libusb_config_descriptor* platform_config;
244 rv = libusb_get_config_descriptor(platform_device_, i, &platform_config);
245 if (rv != LIBUSB_SUCCESS) {
246 USB_LOG(EVENT) << "Failed to get config descriptor: "
247 << ConvertPlatformUsbErrorToString(rv);
248 continue;
251 UsbConfigDescriptor config_descriptor;
252 ConvertConfigDescriptor(platform_config, &config_descriptor);
253 configurations_.push_back(config_descriptor);
254 libusb_free_config_descriptor(platform_config);
256 } else {
257 USB_LOG(EVENT) << "Failed to get device descriptor: "
258 << ConvertPlatformUsbErrorToString(rv);
262 void UsbDeviceImpl::RefreshActiveConfiguration() {
263 active_configuration_ = nullptr;
264 libusb_config_descriptor* platform_config;
265 int rv =
266 libusb_get_active_config_descriptor(platform_device_, &platform_config);
267 if (rv != LIBUSB_SUCCESS) {
268 USB_LOG(EVENT) << "Failed to get config descriptor: "
269 << ConvertPlatformUsbErrorToString(rv);
270 return;
273 for (const auto& config : configurations_) {
274 if (config.configuration_value == platform_config->bConfigurationValue) {
275 active_configuration_ = &config;
276 break;
280 libusb_free_config_descriptor(platform_config);
283 #if defined(OS_CHROMEOS)
285 void UsbDeviceImpl::OnOpenRequestComplete(const OpenCallback& callback,
286 dbus::FileDescriptor fd) {
287 blocking_task_runner_->PostTask(
288 FROM_HERE, base::Bind(&UsbDeviceImpl::OpenOnBlockingThreadWithFd, this,
289 base::Passed(&fd), callback));
292 void UsbDeviceImpl::OpenOnBlockingThreadWithFd(dbus::FileDescriptor fd,
293 const OpenCallback& callback) {
294 fd.CheckValidity();
295 if (!fd.is_valid()) {
296 USB_LOG(EVENT) << "Did not get valid device handle from permission broker.";
297 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
298 return;
301 PlatformUsbDeviceHandle handle;
302 const int rv = libusb_open_fd(platform_device_, fd.TakeValue(), &handle);
303 if (LIBUSB_SUCCESS == rv) {
304 task_runner_->PostTask(
305 FROM_HERE, base::Bind(&UsbDeviceImpl::Opened, this, handle, callback));
306 } else {
307 USB_LOG(EVENT) << "Failed to open device: "
308 << ConvertPlatformUsbErrorToString(rv);
309 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
313 #endif // defined(OS_CHROMEOS)
315 void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback& callback) {
316 PlatformUsbDeviceHandle handle;
317 const int rv = libusb_open(platform_device_, &handle);
318 if (LIBUSB_SUCCESS == rv) {
319 task_runner_->PostTask(
320 FROM_HERE, base::Bind(&UsbDeviceImpl::Opened, this, handle, callback));
321 } else {
322 USB_LOG(EVENT) << "Failed to open device: "
323 << ConvertPlatformUsbErrorToString(rv);
324 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
328 void UsbDeviceImpl::Opened(PlatformUsbDeviceHandle platform_handle,
329 const OpenCallback& callback) {
330 DCHECK(thread_checker_.CalledOnValidThread());
331 scoped_refptr<UsbDeviceHandleImpl> device_handle = new UsbDeviceHandleImpl(
332 context_, this, platform_handle, blocking_task_runner_);
333 handles_.push_back(device_handle);
334 callback.Run(device_handle);
337 } // namespace device