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"
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)
29 #include "device/udev_linux/scoped_udev.h"
30 #endif // defined(USE_UDEV)
36 #if defined(OS_CHROMEOS)
37 void OnRequestUsbAccessReplied(
38 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
39 const base::Callback<void(bool success)>& callback,
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;
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;
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;
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;
101 return USB_USAGE_DATA;
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,
125 : UsbDevice(vendor_id, product_id, unique_id),
126 platform_device_(platform_device),
127 current_configuration_cached_(false),
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) {
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)));
151 const char* value = udev_device_get_sysattr_value(device.get(), "busnum");
152 if (!value || bus_number != value) {
155 value = udev_device_get_sysattr_value(device.get(), "devnum");
156 if (!value || device_address != value) {
160 value = udev_device_get_sysattr_value(device.get(), "manufacturer");
162 manufacturer_ = base::UTF8ToUTF16(value);
164 value = udev_device_get_sysattr_value(device.get(), "product");
166 product_ = base::UTF8ToUTF16(value);
168 value = udev_device_get_sysattr_value(device.get(), "serial");
170 serial_number_ = base::UTF8ToUTF16(value);
176 strings_cached_ = false;
180 UsbDeviceImpl::~UsbDeviceImpl() {
181 DCHECK(thread_checker_.CalledOnValidThread());
182 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
184 (*it)->InternalClose();
186 STLClearObject(&handles_);
187 libusb_unref_device(platform_device_);
190 #if defined(OS_CHROMEOS)
192 void UsbDeviceImpl::RequestUsbAccess(
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.";
208 ui_task_runner_->PostTask(
210 base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess,
211 base::Unretained(client),
215 base::Bind(&OnRequestUsbAccessReplied,
216 base::ThreadTaskRunnerHandle::Get(),
223 scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() {
224 DCHECK(thread_checker_.CalledOnValidThread());
225 PlatformUsbDeviceHandle handle;
226 const int rv = libusb_open(platform_device_, &handle);
227 if (LIBUSB_SUCCESS == rv) {
229 if (!current_configuration_cached_) {
230 libusb_close(handle);
233 scoped_refptr<UsbDeviceHandleImpl> device_handle =
234 new UsbDeviceHandleImpl(context_, this, handle, current_configuration_);
235 handles_.push_back(device_handle);
236 return device_handle;
238 VLOG(1) << "Failed to open device: " << ConvertPlatformUsbErrorToString(rv);
243 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
244 DCHECK(thread_checker_.CalledOnValidThread());
246 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
248 if (it->get() == handle.get()) {
249 (*it)->InternalClose();
257 const UsbConfigDescriptor& UsbDeviceImpl::GetConfiguration() {
258 DCHECK(thread_checker_.CalledOnValidThread());
260 if (!current_configuration_cached_) {
261 libusb_config_descriptor* platform_config;
263 libusb_get_active_config_descriptor(platform_device_, &platform_config);
264 if (rv != LIBUSB_SUCCESS) {
265 VLOG(1) << "Failed to get config descriptor: "
266 << ConvertPlatformUsbErrorToString(rv);
267 return current_configuration_;
270 current_configuration_.configuration_value =
271 platform_config->bConfigurationValue;
272 current_configuration_.self_powered =
273 (platform_config->bmAttributes & 0x40) != 0;
274 current_configuration_.remote_wakeup =
275 (platform_config->bmAttributes & 0x20) != 0;
276 current_configuration_.maximum_power = platform_config->MaxPower * 2;
278 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
279 const struct libusb_interface* platform_interface =
280 &platform_config->interface[i];
281 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
282 const struct libusb_interface_descriptor* platform_alt_setting =
283 &platform_interface->altsetting[j];
284 UsbInterfaceDescriptor interface;
286 interface.interface_number = platform_alt_setting->bInterfaceNumber;
287 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
288 interface.interface_class = platform_alt_setting->bInterfaceClass;
289 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
290 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
292 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
293 const struct libusb_endpoint_descriptor* platform_endpoint =
294 &platform_alt_setting->endpoint[k];
295 UsbEndpointDescriptor endpoint;
297 endpoint.address = platform_endpoint->bEndpointAddress;
298 endpoint.direction = GetDirection(platform_endpoint);
299 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
300 endpoint.synchronization_type =
301 GetSynchronizationType(platform_endpoint);
302 endpoint.transfer_type = GetTransferType(platform_endpoint);
303 endpoint.usage_type = GetUsageType(platform_endpoint);
304 endpoint.polling_interval = platform_endpoint->bInterval;
305 endpoint.extra_data = std::vector<uint8_t>(
306 platform_endpoint->extra,
307 platform_endpoint->extra + platform_endpoint->extra_length);
309 interface.endpoints.push_back(endpoint);
312 interface.extra_data = std::vector<uint8_t>(
313 platform_alt_setting->extra,
314 platform_alt_setting->extra + platform_alt_setting->extra_length);
316 current_configuration_.interfaces.push_back(interface);
320 current_configuration_.extra_data = std::vector<uint8_t>(
321 platform_config->extra,
322 platform_config->extra + platform_config->extra_length);
324 libusb_free_config_descriptor(platform_config);
325 current_configuration_cached_ = true;
328 return current_configuration_;
331 bool UsbDeviceImpl::GetManufacturer(base::string16* manufacturer) {
332 DCHECK(thread_checker_.CalledOnValidThread());
334 #if !defined(USE_UDEV)
335 if (!strings_cached_) {
340 *manufacturer = manufacturer_;
341 return !manufacturer_.empty();
344 bool UsbDeviceImpl::GetProduct(base::string16* product) {
345 DCHECK(thread_checker_.CalledOnValidThread());
347 #if !defined(USE_UDEV)
348 if (!strings_cached_) {
354 return !product_.empty();
357 bool UsbDeviceImpl::GetSerialNumber(base::string16* serial_number) {
358 DCHECK(thread_checker_.CalledOnValidThread());
360 #if !defined(USE_UDEV)
361 if (!strings_cached_) {
366 *serial_number = serial_number_;
367 return !serial_number_.empty();
370 void UsbDeviceImpl::OnDisconnect() {
371 DCHECK(thread_checker_.CalledOnValidThread());
372 HandlesVector handles;
373 swap(handles, handles_);
374 for (HandlesVector::iterator it = handles.begin(); it != handles.end(); ++it)
375 (*it)->InternalClose();
378 #if !defined(USE_UDEV)
379 void UsbDeviceImpl::CacheStrings() {
380 DCHECK(thread_checker_.CalledOnValidThread());
381 // This is a non-blocking call as libusb has the descriptor in memory.
382 libusb_device_descriptor desc;
383 const int rv = libusb_get_device_descriptor(platform_device_, &desc);
384 if (rv == LIBUSB_SUCCESS) {
385 scoped_refptr<UsbDeviceHandle> device_handle = Open();
386 if (device_handle.get()) {
387 if (desc.iManufacturer != 0) {
388 device_handle->GetStringDescriptor(desc.iManufacturer, &manufacturer_);
390 if (desc.iProduct != 0) {
391 device_handle->GetStringDescriptor(desc.iProduct, &product_);
393 if (desc.iSerialNumber != 0) {
394 device_handle->GetStringDescriptor(desc.iSerialNumber, &serial_number_);
396 device_handle->Close();
398 VLOG(1) << "Failed to open device to cache string descriptors.";
401 VLOG(1) << "Failed to read device descriptor to cache string descriptors: "
402 << ConvertPlatformUsbErrorToString(rv);
404 strings_cached_ = true;
406 #endif // !defined(USE_UDEV)
408 } // namespace device