ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / device / usb / usb_device_impl.cc
blob3aa9fbaa86db660a20433ba67aebd276f6eb59ea
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/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "components/device_event_log/device_event_log.h"
17 #include "device/usb/usb_context.h"
18 #include "device/usb/usb_descriptors.h"
19 #include "device/usb/usb_device_handle_impl.h"
20 #include "device/usb/usb_error.h"
21 #include "third_party/libusb/src/libusb/libusb.h"
23 #if defined(OS_CHROMEOS)
24 #include "base/sys_info.h"
25 #include "chromeos/dbus/dbus_thread_manager.h"
26 #include "chromeos/dbus/permission_broker_client.h"
27 #endif // defined(OS_CHROMEOS)
29 #if defined(USE_UDEV)
30 #include "device/udev_linux/scoped_udev.h"
31 #endif // defined(USE_UDEV)
33 namespace device {
35 namespace {
37 #if defined(OS_CHROMEOS)
38 void OnRequestUsbAccessReplied(
39 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
40 const base::Callback<void(bool success)>& callback,
41 bool success) {
42 task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
44 #endif // defined(OS_CHROMEOS)
46 UsbEndpointDirection GetDirection(
47 const libusb_endpoint_descriptor* descriptor) {
48 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
49 case LIBUSB_ENDPOINT_IN:
50 return USB_DIRECTION_INBOUND;
51 case LIBUSB_ENDPOINT_OUT:
52 return USB_DIRECTION_OUTBOUND;
53 default:
54 NOTREACHED();
55 return USB_DIRECTION_INBOUND;
59 UsbSynchronizationType GetSynchronizationType(
60 const libusb_endpoint_descriptor* descriptor) {
61 switch ((descriptor->bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2) {
62 case LIBUSB_ISO_SYNC_TYPE_NONE:
63 return USB_SYNCHRONIZATION_NONE;
64 case LIBUSB_ISO_SYNC_TYPE_ASYNC:
65 return USB_SYNCHRONIZATION_ASYNCHRONOUS;
66 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
67 return USB_SYNCHRONIZATION_ADAPTIVE;
68 case LIBUSB_ISO_SYNC_TYPE_SYNC:
69 return USB_SYNCHRONIZATION_SYNCHRONOUS;
70 default:
71 NOTREACHED();
72 return USB_SYNCHRONIZATION_NONE;
76 UsbTransferType GetTransferType(const libusb_endpoint_descriptor* descriptor) {
77 switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
78 case LIBUSB_TRANSFER_TYPE_CONTROL:
79 return USB_TRANSFER_CONTROL;
80 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
81 return USB_TRANSFER_ISOCHRONOUS;
82 case LIBUSB_TRANSFER_TYPE_BULK:
83 return USB_TRANSFER_BULK;
84 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
85 return USB_TRANSFER_INTERRUPT;
86 default:
87 NOTREACHED();
88 return USB_TRANSFER_CONTROL;
92 UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
93 switch ((descriptor->bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4) {
94 case LIBUSB_ISO_USAGE_TYPE_DATA:
95 return USB_USAGE_DATA;
96 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
97 return USB_USAGE_FEEDBACK;
98 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
99 return USB_USAGE_EXPLICIT_FEEDBACK;
100 default:
101 NOTREACHED();
102 return USB_USAGE_DATA;
106 } // namespace
108 UsbDeviceImpl::UsbDeviceImpl(
109 scoped_refptr<UsbContext> context,
110 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
111 PlatformUsbDevice platform_device,
112 uint16 vendor_id,
113 uint16 product_id,
114 uint32 unique_id)
115 : UsbDevice(vendor_id, product_id, unique_id),
116 platform_device_(platform_device),
117 context_(context),
118 ui_task_runner_(ui_task_runner) {
119 CHECK(platform_device) << "platform_device cannot be NULL";
120 libusb_ref_device(platform_device);
121 RefreshConfiguration();
122 #if defined(USE_UDEV)
123 ScopedUdevPtr udev(udev_new());
124 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get()));
126 udev_enumerate_add_match_subsystem(enumerate.get(), "usb");
127 if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
128 return;
130 std::string bus_number =
131 base::IntToString(libusb_get_bus_number(platform_device));
132 std::string device_address =
133 base::IntToString(libusb_get_device_address(platform_device));
134 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
135 for (udev_list_entry* i = devices; i != NULL;
136 i = udev_list_entry_get_next(i)) {
137 ScopedUdevDevicePtr device(
138 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
139 if (device) {
140 const char* value = udev_device_get_sysattr_value(device.get(), "busnum");
141 if (!value || bus_number != value) {
142 continue;
144 value = udev_device_get_sysattr_value(device.get(), "devnum");
145 if (!value || device_address != value) {
146 continue;
149 #if defined(OS_CHROMEOS)
150 value = udev_device_get_devnode(device.get());
151 if (value) {
152 devnode_ = value;
154 #endif
155 value = udev_device_get_sysattr_value(device.get(), "manufacturer");
156 if (value) {
157 manufacturer_ = base::UTF8ToUTF16(value);
159 value = udev_device_get_sysattr_value(device.get(), "product");
160 if (value) {
161 product_ = base::UTF8ToUTF16(value);
163 value = udev_device_get_sysattr_value(device.get(), "serial");
164 if (value) {
165 serial_number_ = base::UTF8ToUTF16(value);
167 break;
170 #else
171 strings_cached_ = false;
172 #endif
175 UsbDeviceImpl::~UsbDeviceImpl() {
176 // The destructor must be safe to call from any thread.
177 libusb_unref_device(platform_device_);
180 #if defined(OS_CHROMEOS)
182 void UsbDeviceImpl::RequestUsbAccess(
183 int interface_id,
184 const base::Callback<void(bool success)>& callback) {
185 DCHECK(thread_checker_.CalledOnValidThread());
187 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
188 // use permission broker.
189 if (base::SysInfo::IsRunningOnChromeOS()) {
190 chromeos::PermissionBrokerClient* client =
191 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
192 DCHECK(client) << "Could not get permission broker client.";
193 if (!client) {
194 callback.Run(false);
195 return;
198 ui_task_runner_->PostTask(
199 FROM_HERE,
200 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
201 base::Unretained(client),
202 devnode_,
203 interface_id,
204 base::Bind(&OnRequestUsbAccessReplied,
205 base::ThreadTaskRunnerHandle::Get(),
206 callback)));
207 } else {
208 // Not really running on Chrome OS, declare success.
209 callback.Run(true);
213 #endif
215 scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() {
216 DCHECK(thread_checker_.CalledOnValidThread());
217 PlatformUsbDeviceHandle handle;
218 const int rv = libusb_open(platform_device_, &handle);
219 if (LIBUSB_SUCCESS == rv) {
220 scoped_refptr<UsbDeviceHandleImpl> device_handle =
221 new UsbDeviceHandleImpl(context_, this, handle);
222 handles_.push_back(device_handle);
223 return device_handle;
224 } else {
225 USB_LOG(EVENT) << "Failed to open device: "
226 << ConvertPlatformUsbErrorToString(rv);
227 return NULL;
231 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
232 DCHECK(thread_checker_.CalledOnValidThread());
234 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
235 ++it) {
236 if (it->get() == handle.get()) {
237 (*it)->InternalClose();
238 handles_.erase(it);
239 return true;
242 return false;
245 const UsbConfigDescriptor* UsbDeviceImpl::GetConfiguration() {
246 DCHECK(thread_checker_.CalledOnValidThread());
247 return configuration_.get();
250 bool UsbDeviceImpl::GetManufacturer(base::string16* manufacturer) {
251 DCHECK(thread_checker_.CalledOnValidThread());
253 #if !defined(USE_UDEV)
254 if (!strings_cached_) {
255 CacheStrings();
257 #endif
259 *manufacturer = manufacturer_;
260 return !manufacturer_.empty();
263 bool UsbDeviceImpl::GetProduct(base::string16* product) {
264 DCHECK(thread_checker_.CalledOnValidThread());
266 #if !defined(USE_UDEV)
267 if (!strings_cached_) {
268 CacheStrings();
270 #endif
272 *product = product_;
273 return !product_.empty();
276 bool UsbDeviceImpl::GetSerialNumber(base::string16* serial_number) {
277 DCHECK(thread_checker_.CalledOnValidThread());
279 #if !defined(USE_UDEV)
280 if (!strings_cached_) {
281 CacheStrings();
283 #endif
285 *serial_number = serial_number_;
286 return !serial_number_.empty();
289 void UsbDeviceImpl::OnDisconnect() {
290 DCHECK(thread_checker_.CalledOnValidThread());
292 // Swap the list of handles into a local variable because closing all open
293 // handles may release the last reference to this object.
294 HandlesVector handles;
295 swap(handles, handles_);
297 for (const scoped_refptr<UsbDeviceHandleImpl>& handle : handles_) {
298 handle->InternalClose();
302 void UsbDeviceImpl::RefreshConfiguration() {
303 libusb_config_descriptor* platform_config;
304 int rv =
305 libusb_get_active_config_descriptor(platform_device_, &platform_config);
306 if (rv != LIBUSB_SUCCESS) {
307 USB_LOG(EVENT) << "Failed to get config descriptor: "
308 << ConvertPlatformUsbErrorToString(rv);
309 return;
312 configuration_.reset(new UsbConfigDescriptor());
313 configuration_->configuration_value = platform_config->bConfigurationValue;
314 configuration_->self_powered = (platform_config->bmAttributes & 0x40) != 0;
315 configuration_->remote_wakeup = (platform_config->bmAttributes & 0x20) != 0;
316 configuration_->maximum_power = platform_config->MaxPower * 2;
318 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
319 const struct libusb_interface* platform_interface =
320 &platform_config->interface[i];
321 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
322 const struct libusb_interface_descriptor* platform_alt_setting =
323 &platform_interface->altsetting[j];
324 UsbInterfaceDescriptor interface;
326 interface.interface_number = platform_alt_setting->bInterfaceNumber;
327 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
328 interface.interface_class = platform_alt_setting->bInterfaceClass;
329 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
330 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
332 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
333 const struct libusb_endpoint_descriptor* platform_endpoint =
334 &platform_alt_setting->endpoint[k];
335 UsbEndpointDescriptor endpoint;
337 endpoint.address = platform_endpoint->bEndpointAddress;
338 endpoint.direction = GetDirection(platform_endpoint);
339 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
340 endpoint.synchronization_type =
341 GetSynchronizationType(platform_endpoint);
342 endpoint.transfer_type = GetTransferType(platform_endpoint);
343 endpoint.usage_type = GetUsageType(platform_endpoint);
344 endpoint.polling_interval = platform_endpoint->bInterval;
345 endpoint.extra_data = std::vector<uint8_t>(
346 platform_endpoint->extra,
347 platform_endpoint->extra + platform_endpoint->extra_length);
349 interface.endpoints.push_back(endpoint);
352 interface.extra_data = std::vector<uint8_t>(
353 platform_alt_setting->extra,
354 platform_alt_setting->extra + platform_alt_setting->extra_length);
356 configuration_->interfaces.push_back(interface);
360 configuration_->extra_data = std::vector<uint8_t>(
361 platform_config->extra,
362 platform_config->extra + platform_config->extra_length);
364 libusb_free_config_descriptor(platform_config);
367 #if !defined(USE_UDEV)
368 void UsbDeviceImpl::CacheStrings() {
369 DCHECK(thread_checker_.CalledOnValidThread());
370 // This is a non-blocking call as libusb has the descriptor in memory.
371 libusb_device_descriptor desc;
372 const int rv = libusb_get_device_descriptor(platform_device_, &desc);
373 if (rv == LIBUSB_SUCCESS) {
374 scoped_refptr<UsbDeviceHandle> device_handle = Open();
375 if (device_handle.get()) {
376 if (desc.iManufacturer != 0) {
377 device_handle->GetStringDescriptor(desc.iManufacturer, &manufacturer_);
379 if (desc.iProduct != 0) {
380 device_handle->GetStringDescriptor(desc.iProduct, &product_);
382 if (desc.iSerialNumber != 0) {
383 device_handle->GetStringDescriptor(desc.iSerialNumber, &serial_number_);
385 device_handle->Close();
386 } else {
387 USB_LOG(EVENT) << "Failed to open device to cache string descriptors.";
389 } else {
390 USB_LOG(EVENT)
391 << "Failed to read device descriptor to cache string descriptors: "
392 << ConvertPlatformUsbErrorToString(rv);
394 strings_cached_ = true;
396 #endif // !defined(USE_UDEV)
398 } // namespace device