Fix building NaCl in Linux component GN builds.
[chromium-blink-merge.git] / device / usb / usb_device_impl.cc
blob0d9ac46422012978cd6c39d0642aef4b8ae9838f
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 #endif // defined(OS_CHROMEOS)
27 namespace device {
29 namespace {
31 UsbEndpointDirection GetDirection(
32 const libusb_endpoint_descriptor* descriptor) {
33 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
34 case LIBUSB_ENDPOINT_IN:
35 return USB_DIRECTION_INBOUND;
36 case LIBUSB_ENDPOINT_OUT:
37 return USB_DIRECTION_OUTBOUND;
38 default:
39 NOTREACHED();
40 return USB_DIRECTION_INBOUND;
44 UsbSynchronizationType GetSynchronizationType(
45 const libusb_endpoint_descriptor* descriptor) {
46 switch ((descriptor->bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2) {
47 case LIBUSB_ISO_SYNC_TYPE_NONE:
48 return USB_SYNCHRONIZATION_NONE;
49 case LIBUSB_ISO_SYNC_TYPE_ASYNC:
50 return USB_SYNCHRONIZATION_ASYNCHRONOUS;
51 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
52 return USB_SYNCHRONIZATION_ADAPTIVE;
53 case LIBUSB_ISO_SYNC_TYPE_SYNC:
54 return USB_SYNCHRONIZATION_SYNCHRONOUS;
55 default:
56 NOTREACHED();
57 return USB_SYNCHRONIZATION_NONE;
61 UsbTransferType GetTransferType(const libusb_endpoint_descriptor* descriptor) {
62 switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
63 case LIBUSB_TRANSFER_TYPE_CONTROL:
64 return USB_TRANSFER_CONTROL;
65 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
66 return USB_TRANSFER_ISOCHRONOUS;
67 case LIBUSB_TRANSFER_TYPE_BULK:
68 return USB_TRANSFER_BULK;
69 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
70 return USB_TRANSFER_INTERRUPT;
71 default:
72 NOTREACHED();
73 return USB_TRANSFER_CONTROL;
77 UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
78 switch ((descriptor->bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4) {
79 case LIBUSB_ISO_USAGE_TYPE_DATA:
80 return USB_USAGE_DATA;
81 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
82 return USB_USAGE_FEEDBACK;
83 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
84 return USB_USAGE_EXPLICIT_FEEDBACK;
85 default:
86 NOTREACHED();
87 return USB_USAGE_DATA;
91 } // namespace
93 UsbDeviceImpl::UsbDeviceImpl(
94 scoped_refptr<UsbContext> context,
95 PlatformUsbDevice platform_device,
96 uint16 vendor_id,
97 uint16 product_id,
98 uint32 unique_id,
99 const base::string16& manufacturer_string,
100 const base::string16& product_string,
101 const base::string16& serial_number,
102 const std::string& device_node,
103 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
104 : UsbDevice(vendor_id,
105 product_id,
106 unique_id,
107 manufacturer_string,
108 product_string,
109 serial_number),
110 platform_device_(platform_device),
111 #if defined(OS_CHROMEOS)
112 devnode_(device_node),
113 #endif // defined(OS_CHROMEOS)
114 context_(context),
115 task_runner_(base::ThreadTaskRunnerHandle::Get()),
116 blocking_task_runner_(blocking_task_runner) {
117 CHECK(platform_device) << "platform_device cannot be NULL";
118 libusb_ref_device(platform_device);
119 RefreshConfiguration();
122 UsbDeviceImpl::~UsbDeviceImpl() {
123 // The destructor must be safe to call from any thread.
124 libusb_unref_device(platform_device_);
127 #if defined(OS_CHROMEOS)
129 void UsbDeviceImpl::CheckUsbAccess(const ResultCallback& callback) {
130 DCHECK(thread_checker_.CalledOnValidThread());
131 chromeos::PermissionBrokerClient* client =
132 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
133 DCHECK(client) << "Could not get permission broker client.";
134 client->CheckPathAccess(devnode_, callback);
137 void UsbDeviceImpl::RequestUsbAccess(int interface_id,
138 const ResultCallback& callback) {
139 DCHECK(thread_checker_.CalledOnValidThread());
140 chromeos::PermissionBrokerClient* client =
141 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
142 DCHECK(client) << "Could not get permission broker client.";
143 client->RequestPathAccess(devnode_, interface_id, callback);
146 #endif
148 void UsbDeviceImpl::Open(const OpenCallback& callback) {
149 DCHECK(thread_checker_.CalledOnValidThread());
150 blocking_task_runner_->PostTask(
151 FROM_HERE,
152 base::Bind(&UsbDeviceImpl::OpenOnBlockingThread, this, callback));
155 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
156 DCHECK(thread_checker_.CalledOnValidThread());
158 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
159 ++it) {
160 if (it->get() == handle.get()) {
161 (*it)->InternalClose();
162 handles_.erase(it);
163 return true;
166 return false;
169 const UsbConfigDescriptor* UsbDeviceImpl::GetConfiguration() {
170 DCHECK(thread_checker_.CalledOnValidThread());
171 return configuration_.get();
174 void UsbDeviceImpl::OnDisconnect() {
175 DCHECK(thread_checker_.CalledOnValidThread());
177 // Swap the list of handles into a local variable because closing all open
178 // handles may release the last reference to this object.
179 HandlesVector handles;
180 swap(handles, handles_);
182 for (const scoped_refptr<UsbDeviceHandleImpl>& handle : handles_) {
183 handle->InternalClose();
187 void UsbDeviceImpl::RefreshConfiguration() {
188 libusb_config_descriptor* platform_config;
189 int rv =
190 libusb_get_active_config_descriptor(platform_device_, &platform_config);
191 if (rv != LIBUSB_SUCCESS) {
192 USB_LOG(EVENT) << "Failed to get config descriptor: "
193 << ConvertPlatformUsbErrorToString(rv);
194 return;
197 configuration_.reset(new UsbConfigDescriptor());
198 configuration_->configuration_value = platform_config->bConfigurationValue;
199 configuration_->self_powered = (platform_config->bmAttributes & 0x40) != 0;
200 configuration_->remote_wakeup = (platform_config->bmAttributes & 0x20) != 0;
201 configuration_->maximum_power = platform_config->MaxPower * 2;
203 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
204 const struct libusb_interface* platform_interface =
205 &platform_config->interface[i];
206 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
207 const struct libusb_interface_descriptor* platform_alt_setting =
208 &platform_interface->altsetting[j];
209 UsbInterfaceDescriptor interface;
211 interface.interface_number = platform_alt_setting->bInterfaceNumber;
212 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
213 interface.interface_class = platform_alt_setting->bInterfaceClass;
214 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
215 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
217 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
218 const struct libusb_endpoint_descriptor* platform_endpoint =
219 &platform_alt_setting->endpoint[k];
220 UsbEndpointDescriptor endpoint;
222 endpoint.address = platform_endpoint->bEndpointAddress;
223 endpoint.direction = GetDirection(platform_endpoint);
224 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
225 endpoint.synchronization_type =
226 GetSynchronizationType(platform_endpoint);
227 endpoint.transfer_type = GetTransferType(platform_endpoint);
228 endpoint.usage_type = GetUsageType(platform_endpoint);
229 endpoint.polling_interval = platform_endpoint->bInterval;
230 endpoint.extra_data = std::vector<uint8_t>(
231 platform_endpoint->extra,
232 platform_endpoint->extra + platform_endpoint->extra_length);
234 interface.endpoints.push_back(endpoint);
237 interface.extra_data = std::vector<uint8_t>(
238 platform_alt_setting->extra,
239 platform_alt_setting->extra + platform_alt_setting->extra_length);
241 configuration_->interfaces.push_back(interface);
245 configuration_->extra_data = std::vector<uint8_t>(
246 platform_config->extra,
247 platform_config->extra + platform_config->extra_length);
249 libusb_free_config_descriptor(platform_config);
252 void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback& callback) {
253 PlatformUsbDeviceHandle handle;
254 const int rv = libusb_open(platform_device_, &handle);
255 if (LIBUSB_SUCCESS == rv) {
256 task_runner_->PostTask(
257 FROM_HERE, base::Bind(&UsbDeviceImpl::Opened, this, handle, callback));
258 } else {
259 USB_LOG(EVENT) << "Failed to open device: "
260 << ConvertPlatformUsbErrorToString(rv);
261 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
265 void UsbDeviceImpl::Opened(PlatformUsbDeviceHandle platform_handle,
266 const OpenCallback& callback) {
267 DCHECK(thread_checker_.CalledOnValidThread());
268 scoped_refptr<UsbDeviceHandleImpl> device_handle = new UsbDeviceHandleImpl(
269 context_, this, platform_handle, blocking_task_runner_);
270 handles_.push_back(device_handle);
271 callback.Run(device_handle);
274 } // namespace device