[SyncFS] Run RemoteToLocalSyncer as a background task
[chromium-blink-merge.git] / device / usb / usb_device_impl.cc
bloba9838dc6a08005519b9f3e5e82f239a78a3ab5bd
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/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "device/usb/usb_context.h"
15 #include "device/usb/usb_descriptors.h"
16 #include "device/usb/usb_device_handle_impl.h"
17 #include "device/usb/usb_error.h"
18 #include "third_party/libusb/src/libusb/libusb.h"
20 #if defined(OS_CHROMEOS)
21 #include "base/sys_info.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/permission_broker_client.h"
24 #endif // defined(OS_CHROMEOS)
26 namespace device {
28 namespace {
30 #if defined(OS_CHROMEOS)
31 void OnRequestUsbAccessReplied(
32 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
33 const base::Callback<void(bool success)>& callback,
34 bool success) {
35 task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
37 #endif // defined(OS_CHROMEOS)
39 UsbEndpointDirection GetDirection(
40 const libusb_endpoint_descriptor* descriptor) {
41 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
42 case LIBUSB_ENDPOINT_IN:
43 return USB_DIRECTION_INBOUND;
44 case LIBUSB_ENDPOINT_OUT:
45 return USB_DIRECTION_OUTBOUND;
46 default:
47 NOTREACHED();
48 return USB_DIRECTION_INBOUND;
52 UsbSynchronizationType GetSynchronizationType(
53 const libusb_endpoint_descriptor* descriptor) {
54 switch (descriptor->bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) {
55 case LIBUSB_ISO_SYNC_TYPE_NONE:
56 return USB_SYNCHRONIZATION_NONE;
57 case LIBUSB_ISO_SYNC_TYPE_ASYNC:
58 return USB_SYNCHRONIZATION_ASYNCHRONOUS;
59 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
60 return USB_SYNCHRONIZATION_ADAPTIVE;
61 case LIBUSB_ISO_SYNC_TYPE_SYNC:
62 return USB_SYNCHRONIZATION_SYNCHRONOUS;
63 default:
64 NOTREACHED();
65 return USB_SYNCHRONIZATION_NONE;
69 UsbTransferType GetTransferType(const libusb_endpoint_descriptor* descriptor) {
70 switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
71 case LIBUSB_TRANSFER_TYPE_CONTROL:
72 return USB_TRANSFER_CONTROL;
73 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
74 return USB_TRANSFER_ISOCHRONOUS;
75 case LIBUSB_TRANSFER_TYPE_BULK:
76 return USB_TRANSFER_BULK;
77 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
78 return USB_TRANSFER_INTERRUPT;
79 default:
80 NOTREACHED();
81 return USB_TRANSFER_CONTROL;
85 UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
86 switch (descriptor->bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) {
87 case LIBUSB_ISO_USAGE_TYPE_DATA:
88 return USB_USAGE_DATA;
89 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
90 return USB_USAGE_FEEDBACK;
91 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
92 return USB_USAGE_EXPLICIT_FEEDBACK;
93 default:
94 NOTREACHED();
95 return USB_USAGE_DATA;
99 } // namespace
101 UsbDevice::UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
102 : vendor_id_(vendor_id), product_id_(product_id), unique_id_(unique_id) {
105 UsbDevice::~UsbDevice() {
108 void UsbDevice::NotifyDisconnect() {
109 FOR_EACH_OBSERVER(Observer, observer_list_, OnDisconnect(this));
112 UsbDeviceImpl::UsbDeviceImpl(
113 scoped_refptr<UsbContext> context,
114 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
115 PlatformUsbDevice platform_device,
116 uint16 vendor_id,
117 uint16 product_id,
118 uint32 unique_id)
119 : UsbDevice(vendor_id, product_id, unique_id),
120 platform_device_(platform_device),
121 current_configuration_cached_(false),
122 context_(context),
123 ui_task_runner_(ui_task_runner) {
124 CHECK(platform_device) << "platform_device cannot be NULL";
125 libusb_ref_device(platform_device);
128 UsbDeviceImpl::~UsbDeviceImpl() {
129 DCHECK(thread_checker_.CalledOnValidThread());
130 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
131 ++it) {
132 (*it)->InternalClose();
134 STLClearObject(&handles_);
135 libusb_unref_device(platform_device_);
138 #if defined(OS_CHROMEOS)
140 void UsbDeviceImpl::RequestUsbAccess(
141 int interface_id,
142 const base::Callback<void(bool success)>& callback) {
143 DCHECK(thread_checker_.CalledOnValidThread());
145 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
146 // use permission broker.
147 if (base::SysInfo::IsRunningOnChromeOS()) {
148 chromeos::PermissionBrokerClient* client =
149 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
150 DCHECK(client) << "Could not get permission broker client.";
151 if (!client) {
152 callback.Run(false);
153 return;
156 ui_task_runner_->PostTask(
157 FROM_HERE,
158 base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess,
159 base::Unretained(client),
160 vendor_id(),
161 product_id(),
162 interface_id,
163 base::Bind(&OnRequestUsbAccessReplied,
164 base::ThreadTaskRunnerHandle::Get(),
165 callback)));
169 #endif
171 scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() {
172 DCHECK(thread_checker_.CalledOnValidThread());
173 PlatformUsbDeviceHandle handle;
174 const int rv = libusb_open(platform_device_, &handle);
175 if (LIBUSB_SUCCESS == rv) {
176 GetConfiguration();
177 if (!current_configuration_cached_) {
178 return NULL;
180 scoped_refptr<UsbDeviceHandleImpl> device_handle =
181 new UsbDeviceHandleImpl(context_, this, handle, current_configuration_);
182 handles_.push_back(device_handle);
183 return device_handle;
184 } else {
185 VLOG(1) << "Failed to open device: " << ConvertPlatformUsbErrorToString(rv);
186 return NULL;
190 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
191 DCHECK(thread_checker_.CalledOnValidThread());
193 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
194 ++it) {
195 if (it->get() == handle.get()) {
196 (*it)->InternalClose();
197 handles_.erase(it);
198 return true;
201 return false;
204 const UsbConfigDescriptor& UsbDeviceImpl::GetConfiguration() {
205 DCHECK(thread_checker_.CalledOnValidThread());
207 if (!current_configuration_cached_) {
208 libusb_config_descriptor* platform_config;
209 const int rv =
210 libusb_get_active_config_descriptor(platform_device_, &platform_config);
211 if (rv != LIBUSB_SUCCESS) {
212 VLOG(1) << "Failed to get config descriptor: "
213 << ConvertPlatformUsbErrorToString(rv);
214 return current_configuration_;
217 current_configuration_.configuration_value =
218 platform_config->bConfigurationValue;
219 current_configuration_.self_powered =
220 (platform_config->bmAttributes & 0x40) != 0;
221 current_configuration_.remote_wakeup =
222 (platform_config->bmAttributes & 0x20) != 0;
223 current_configuration_.maximum_power = platform_config->MaxPower * 2;
225 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
226 const struct libusb_interface* platform_interface =
227 &platform_config->interface[i];
228 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
229 const struct libusb_interface_descriptor* platform_alt_setting =
230 &platform_interface->altsetting[j];
231 UsbInterfaceDescriptor interface;
233 interface.interface_number = platform_alt_setting->bInterfaceNumber;
234 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
235 interface.interface_class = platform_alt_setting->bInterfaceClass;
236 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
237 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
239 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
240 const struct libusb_endpoint_descriptor* platform_endpoint =
241 &platform_alt_setting->endpoint[k];
242 UsbEndpointDescriptor endpoint;
244 endpoint.address = platform_endpoint->bEndpointAddress;
245 endpoint.direction = GetDirection(platform_endpoint);
246 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
247 endpoint.synchronization_type =
248 GetSynchronizationType(platform_endpoint);
249 endpoint.transfer_type = GetTransferType(platform_endpoint);
250 endpoint.usage_type = GetUsageType(platform_endpoint);
251 endpoint.polling_interval = platform_endpoint->bInterval;
252 endpoint.extra_data = std::vector<uint8_t>(
253 platform_endpoint->extra,
254 platform_endpoint->extra + platform_endpoint->extra_length);
256 interface.endpoints.push_back(endpoint);
259 interface.extra_data = std::vector<uint8_t>(
260 platform_alt_setting->extra,
261 platform_alt_setting->extra + platform_alt_setting->extra_length);
263 current_configuration_.interfaces.push_back(interface);
267 current_configuration_.extra_data = std::vector<uint8_t>(
268 platform_config->extra,
269 platform_config->extra + platform_config->extra_length);
271 libusb_free_config_descriptor(platform_config);
272 current_configuration_cached_ = true;
275 return current_configuration_;
278 void UsbDeviceImpl::OnDisconnect() {
279 DCHECK(thread_checker_.CalledOnValidThread());
280 HandlesVector handles;
281 swap(handles, handles_);
282 for (HandlesVector::iterator it = handles.begin(); it != handles.end(); ++it)
283 (*it)->InternalClose();
286 } // namespace device