Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / device / usb / usb_device_impl.cc
blob58150aab84ecb94236cae3583c4442db2bb18eb9
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 "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 "base/sys_info.h"
24 #include "chromeos/dbus/dbus_thread_manager.h"
25 #include "chromeos/dbus/permission_broker_client.h"
26 #endif // defined(OS_CHROMEOS)
28 #if defined(USE_UDEV)
29 #include "device/udev_linux/scoped_udev.h"
30 #endif // defined(USE_UDEV)
32 namespace device {
34 namespace {
36 #if defined(OS_CHROMEOS)
37 void OnRequestUsbAccessReplied(
38 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
39 const base::Callback<void(bool success)>& callback,
40 bool success) {
41 task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
43 #endif // defined(OS_CHROMEOS)
45 UsbEndpointDirection GetDirection(
46 const libusb_endpoint_descriptor* descriptor) {
47 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
48 case LIBUSB_ENDPOINT_IN:
49 return USB_DIRECTION_INBOUND;
50 case LIBUSB_ENDPOINT_OUT:
51 return USB_DIRECTION_OUTBOUND;
52 default:
53 NOTREACHED();
54 return USB_DIRECTION_INBOUND;
58 UsbSynchronizationType GetSynchronizationType(
59 const libusb_endpoint_descriptor* descriptor) {
60 switch ((descriptor->bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2) {
61 case LIBUSB_ISO_SYNC_TYPE_NONE:
62 return USB_SYNCHRONIZATION_NONE;
63 case LIBUSB_ISO_SYNC_TYPE_ASYNC:
64 return USB_SYNCHRONIZATION_ASYNCHRONOUS;
65 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
66 return USB_SYNCHRONIZATION_ADAPTIVE;
67 case LIBUSB_ISO_SYNC_TYPE_SYNC:
68 return USB_SYNCHRONIZATION_SYNCHRONOUS;
69 default:
70 NOTREACHED();
71 return USB_SYNCHRONIZATION_NONE;
75 UsbTransferType GetTransferType(const libusb_endpoint_descriptor* descriptor) {
76 switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
77 case LIBUSB_TRANSFER_TYPE_CONTROL:
78 return USB_TRANSFER_CONTROL;
79 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
80 return USB_TRANSFER_ISOCHRONOUS;
81 case LIBUSB_TRANSFER_TYPE_BULK:
82 return USB_TRANSFER_BULK;
83 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
84 return USB_TRANSFER_INTERRUPT;
85 default:
86 NOTREACHED();
87 return USB_TRANSFER_CONTROL;
91 UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
92 switch ((descriptor->bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4) {
93 case LIBUSB_ISO_USAGE_TYPE_DATA:
94 return USB_USAGE_DATA;
95 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
96 return USB_USAGE_FEEDBACK;
97 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
98 return USB_USAGE_EXPLICIT_FEEDBACK;
99 default:
100 NOTREACHED();
101 return USB_USAGE_DATA;
105 } // namespace
107 UsbDevice::UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
108 : vendor_id_(vendor_id), product_id_(product_id), unique_id_(unique_id) {
111 UsbDevice::~UsbDevice() {
114 void UsbDevice::NotifyDisconnect() {
115 FOR_EACH_OBSERVER(Observer, observer_list_, OnDisconnect(this));
118 UsbDeviceImpl::UsbDeviceImpl(
119 scoped_refptr<UsbContext> context,
120 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
121 PlatformUsbDevice platform_device,
122 uint16 vendor_id,
123 uint16 product_id,
124 uint32 unique_id)
125 : UsbDevice(vendor_id, product_id, unique_id),
126 platform_device_(platform_device),
127 current_configuration_cached_(false),
128 context_(context),
129 ui_task_runner_(ui_task_runner) {
130 CHECK(platform_device) << "platform_device cannot be NULL";
131 libusb_ref_device(platform_device);
133 #if defined(USE_UDEV)
134 ScopedUdevPtr udev(udev_new());
135 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get()));
137 udev_enumerate_add_match_subsystem(enumerate.get(), "usb");
138 if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
139 return;
141 std::string bus_number =
142 base::IntToString(libusb_get_bus_number(platform_device));
143 std::string device_address =
144 base::IntToString(libusb_get_device_address(platform_device));
145 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
146 for (udev_list_entry* i = devices; i != NULL;
147 i = udev_list_entry_get_next(i)) {
148 ScopedUdevDevicePtr device(
149 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
150 if (device) {
151 const char* value = udev_device_get_sysattr_value(device.get(), "busnum");
152 if (!value || bus_number != value) {
153 continue;
155 value = udev_device_get_sysattr_value(device.get(), "devnum");
156 if (!value || device_address != value) {
157 continue;
160 value = udev_device_get_sysattr_value(device.get(), "manufacturer");
161 if (value) {
162 manufacturer_ = base::UTF8ToUTF16(value);
164 value = udev_device_get_sysattr_value(device.get(), "product");
165 if (value) {
166 product_ = base::UTF8ToUTF16(value);
168 value = udev_device_get_sysattr_value(device.get(), "serial");
169 if (value) {
170 serial_number_ = base::UTF8ToUTF16(value);
172 break;
175 #else
176 strings_cached_ = false;
177 #endif
180 UsbDeviceImpl::~UsbDeviceImpl() {
181 DCHECK(thread_checker_.CalledOnValidThread());
182 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
183 ++it) {
184 (*it)->InternalClose();
186 STLClearObject(&handles_);
187 libusb_unref_device(platform_device_);
190 #if defined(OS_CHROMEOS)
192 void UsbDeviceImpl::RequestUsbAccess(
193 int interface_id,
194 const base::Callback<void(bool success)>& callback) {
195 DCHECK(thread_checker_.CalledOnValidThread());
197 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
198 // use permission broker.
199 if (base::SysInfo::IsRunningOnChromeOS()) {
200 chromeos::PermissionBrokerClient* client =
201 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
202 DCHECK(client) << "Could not get permission broker client.";
203 if (!client) {
204 callback.Run(false);
205 return;
208 ui_task_runner_->PostTask(
209 FROM_HERE,
210 base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess,
211 base::Unretained(client),
212 vendor_id(),
213 product_id(),
214 interface_id,
215 base::Bind(&OnRequestUsbAccessReplied,
216 base::ThreadTaskRunnerHandle::Get(),
217 callback)));
218 } else {
219 // Not really running on Chrome OS, declare success.
220 callback.Run(true);
224 #endif
226 scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() {
227 DCHECK(thread_checker_.CalledOnValidThread());
228 PlatformUsbDeviceHandle handle;
229 const int rv = libusb_open(platform_device_, &handle);
230 if (LIBUSB_SUCCESS == rv) {
231 GetConfiguration();
232 if (!current_configuration_cached_) {
233 libusb_close(handle);
234 return NULL;
236 scoped_refptr<UsbDeviceHandleImpl> device_handle =
237 new UsbDeviceHandleImpl(context_, this, handle, current_configuration_);
238 handles_.push_back(device_handle);
239 return device_handle;
240 } else {
241 VLOG(1) << "Failed to open device: " << ConvertPlatformUsbErrorToString(rv);
242 return NULL;
246 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
247 DCHECK(thread_checker_.CalledOnValidThread());
249 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
250 ++it) {
251 if (it->get() == handle.get()) {
252 (*it)->InternalClose();
253 handles_.erase(it);
254 return true;
257 return false;
260 const UsbConfigDescriptor& UsbDeviceImpl::GetConfiguration() {
261 DCHECK(thread_checker_.CalledOnValidThread());
263 if (!current_configuration_cached_) {
264 libusb_config_descriptor* platform_config;
265 const int rv =
266 libusb_get_active_config_descriptor(platform_device_, &platform_config);
267 if (rv != LIBUSB_SUCCESS) {
268 VLOG(1) << "Failed to get config descriptor: "
269 << ConvertPlatformUsbErrorToString(rv);
270 return current_configuration_;
273 current_configuration_.configuration_value =
274 platform_config->bConfigurationValue;
275 current_configuration_.self_powered =
276 (platform_config->bmAttributes & 0x40) != 0;
277 current_configuration_.remote_wakeup =
278 (platform_config->bmAttributes & 0x20) != 0;
279 current_configuration_.maximum_power = platform_config->MaxPower * 2;
281 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
282 const struct libusb_interface* platform_interface =
283 &platform_config->interface[i];
284 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
285 const struct libusb_interface_descriptor* platform_alt_setting =
286 &platform_interface->altsetting[j];
287 UsbInterfaceDescriptor interface;
289 interface.interface_number = platform_alt_setting->bInterfaceNumber;
290 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
291 interface.interface_class = platform_alt_setting->bInterfaceClass;
292 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
293 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
295 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
296 const struct libusb_endpoint_descriptor* platform_endpoint =
297 &platform_alt_setting->endpoint[k];
298 UsbEndpointDescriptor endpoint;
300 endpoint.address = platform_endpoint->bEndpointAddress;
301 endpoint.direction = GetDirection(platform_endpoint);
302 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
303 endpoint.synchronization_type =
304 GetSynchronizationType(platform_endpoint);
305 endpoint.transfer_type = GetTransferType(platform_endpoint);
306 endpoint.usage_type = GetUsageType(platform_endpoint);
307 endpoint.polling_interval = platform_endpoint->bInterval;
308 endpoint.extra_data = std::vector<uint8_t>(
309 platform_endpoint->extra,
310 platform_endpoint->extra + platform_endpoint->extra_length);
312 interface.endpoints.push_back(endpoint);
315 interface.extra_data = std::vector<uint8_t>(
316 platform_alt_setting->extra,
317 platform_alt_setting->extra + platform_alt_setting->extra_length);
319 current_configuration_.interfaces.push_back(interface);
323 current_configuration_.extra_data = std::vector<uint8_t>(
324 platform_config->extra,
325 platform_config->extra + platform_config->extra_length);
327 libusb_free_config_descriptor(platform_config);
328 current_configuration_cached_ = true;
331 return current_configuration_;
334 bool UsbDeviceImpl::GetManufacturer(base::string16* manufacturer) {
335 DCHECK(thread_checker_.CalledOnValidThread());
337 #if !defined(USE_UDEV)
338 if (!strings_cached_) {
339 CacheStrings();
341 #endif
343 *manufacturer = manufacturer_;
344 return !manufacturer_.empty();
347 bool UsbDeviceImpl::GetProduct(base::string16* product) {
348 DCHECK(thread_checker_.CalledOnValidThread());
350 #if !defined(USE_UDEV)
351 if (!strings_cached_) {
352 CacheStrings();
354 #endif
356 *product = product_;
357 return !product_.empty();
360 bool UsbDeviceImpl::GetSerialNumber(base::string16* serial_number) {
361 DCHECK(thread_checker_.CalledOnValidThread());
363 #if !defined(USE_UDEV)
364 if (!strings_cached_) {
365 CacheStrings();
367 #endif
369 *serial_number = serial_number_;
370 return !serial_number_.empty();
373 void UsbDeviceImpl::OnDisconnect() {
374 DCHECK(thread_checker_.CalledOnValidThread());
375 HandlesVector handles;
376 swap(handles, handles_);
377 for (HandlesVector::iterator it = handles.begin(); it != handles.end(); ++it)
378 (*it)->InternalClose();
381 #if !defined(USE_UDEV)
382 void UsbDeviceImpl::CacheStrings() {
383 DCHECK(thread_checker_.CalledOnValidThread());
384 // This is a non-blocking call as libusb has the descriptor in memory.
385 libusb_device_descriptor desc;
386 const int rv = libusb_get_device_descriptor(platform_device_, &desc);
387 if (rv == LIBUSB_SUCCESS) {
388 scoped_refptr<UsbDeviceHandle> device_handle = Open();
389 if (device_handle.get()) {
390 if (desc.iManufacturer != 0) {
391 device_handle->GetStringDescriptor(desc.iManufacturer, &manufacturer_);
393 if (desc.iProduct != 0) {
394 device_handle->GetStringDescriptor(desc.iProduct, &product_);
396 if (desc.iSerialNumber != 0) {
397 device_handle->GetStringDescriptor(desc.iSerialNumber, &serial_number_);
399 device_handle->Close();
400 } else {
401 VLOG(1) << "Failed to open device to cache string descriptors.";
403 } else {
404 VLOG(1) << "Failed to read device descriptor to cache string descriptors: "
405 << ConvertPlatformUsbErrorToString(rv);
407 strings_cached_ = true;
409 #endif // !defined(USE_UDEV)
411 } // namespace device