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/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
) {
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
) {
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");
161 manufacturer_
= value
? value
: "";
162 value
= udev_device_get_sysattr_value(device
.get(), "product");
163 product_
= value
? value
: "";
164 value
= udev_device_get_sysattr_value(device
.get(), "serial");
165 serial_number_
= value
? value
: "";
172 UsbDeviceImpl::~UsbDeviceImpl() {
173 DCHECK(thread_checker_
.CalledOnValidThread());
174 for (HandlesVector::iterator it
= handles_
.begin(); it
!= handles_
.end();
176 (*it
)->InternalClose();
178 STLClearObject(&handles_
);
179 libusb_unref_device(platform_device_
);
182 #if defined(OS_CHROMEOS)
184 void UsbDeviceImpl::RequestUsbAccess(
186 const base::Callback
<void(bool success
)>& callback
) {
187 DCHECK(thread_checker_
.CalledOnValidThread());
189 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
190 // use permission broker.
191 if (base::SysInfo::IsRunningOnChromeOS()) {
192 chromeos::PermissionBrokerClient
* client
=
193 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
194 DCHECK(client
) << "Could not get permission broker client.";
200 ui_task_runner_
->PostTask(
202 base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess
,
203 base::Unretained(client
),
207 base::Bind(&OnRequestUsbAccessReplied
,
208 base::ThreadTaskRunnerHandle::Get(),
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
) {
221 if (!current_configuration_cached_
) {
224 scoped_refptr
<UsbDeviceHandleImpl
> device_handle
=
225 new UsbDeviceHandleImpl(context_
, this, handle
, current_configuration_
);
226 handles_
.push_back(device_handle
);
227 return device_handle
;
229 VLOG(1) << "Failed to open device: " << ConvertPlatformUsbErrorToString(rv
);
234 bool UsbDeviceImpl::Close(scoped_refptr
<UsbDeviceHandle
> handle
) {
235 DCHECK(thread_checker_
.CalledOnValidThread());
237 for (HandlesVector::iterator it
= handles_
.begin(); it
!= handles_
.end();
239 if (it
->get() == handle
.get()) {
240 (*it
)->InternalClose();
248 const UsbConfigDescriptor
& UsbDeviceImpl::GetConfiguration() {
249 DCHECK(thread_checker_
.CalledOnValidThread());
251 if (!current_configuration_cached_
) {
252 libusb_config_descriptor
* platform_config
;
254 libusb_get_active_config_descriptor(platform_device_
, &platform_config
);
255 if (rv
!= LIBUSB_SUCCESS
) {
256 VLOG(1) << "Failed to get config descriptor: "
257 << ConvertPlatformUsbErrorToString(rv
);
258 return current_configuration_
;
261 current_configuration_
.configuration_value
=
262 platform_config
->bConfigurationValue
;
263 current_configuration_
.self_powered
=
264 (platform_config
->bmAttributes
& 0x40) != 0;
265 current_configuration_
.remote_wakeup
=
266 (platform_config
->bmAttributes
& 0x20) != 0;
267 current_configuration_
.maximum_power
= platform_config
->MaxPower
* 2;
269 for (size_t i
= 0; i
< platform_config
->bNumInterfaces
; ++i
) {
270 const struct libusb_interface
* platform_interface
=
271 &platform_config
->interface
[i
];
272 for (int j
= 0; j
< platform_interface
->num_altsetting
; ++j
) {
273 const struct libusb_interface_descriptor
* platform_alt_setting
=
274 &platform_interface
->altsetting
[j
];
275 UsbInterfaceDescriptor interface
;
277 interface
.interface_number
= platform_alt_setting
->bInterfaceNumber
;
278 interface
.alternate_setting
= platform_alt_setting
->bAlternateSetting
;
279 interface
.interface_class
= platform_alt_setting
->bInterfaceClass
;
280 interface
.interface_subclass
= platform_alt_setting
->bInterfaceSubClass
;
281 interface
.interface_protocol
= platform_alt_setting
->bInterfaceProtocol
;
283 for (size_t k
= 0; k
< platform_alt_setting
->bNumEndpoints
; ++k
) {
284 const struct libusb_endpoint_descriptor
* platform_endpoint
=
285 &platform_alt_setting
->endpoint
[k
];
286 UsbEndpointDescriptor endpoint
;
288 endpoint
.address
= platform_endpoint
->bEndpointAddress
;
289 endpoint
.direction
= GetDirection(platform_endpoint
);
290 endpoint
.maximum_packet_size
= platform_endpoint
->wMaxPacketSize
;
291 endpoint
.synchronization_type
=
292 GetSynchronizationType(platform_endpoint
);
293 endpoint
.transfer_type
= GetTransferType(platform_endpoint
);
294 endpoint
.usage_type
= GetUsageType(platform_endpoint
);
295 endpoint
.polling_interval
= platform_endpoint
->bInterval
;
296 endpoint
.extra_data
= std::vector
<uint8_t>(
297 platform_endpoint
->extra
,
298 platform_endpoint
->extra
+ platform_endpoint
->extra_length
);
300 interface
.endpoints
.push_back(endpoint
);
303 interface
.extra_data
= std::vector
<uint8_t>(
304 platform_alt_setting
->extra
,
305 platform_alt_setting
->extra
+ platform_alt_setting
->extra_length
);
307 current_configuration_
.interfaces
.push_back(interface
);
311 current_configuration_
.extra_data
= std::vector
<uint8_t>(
312 platform_config
->extra
,
313 platform_config
->extra
+ platform_config
->extra_length
);
315 libusb_free_config_descriptor(platform_config
);
316 current_configuration_cached_
= true;
319 return current_configuration_
;
322 bool UsbDeviceImpl::GetManufacturer(base::string16
* manufacturer
) {
323 DCHECK(thread_checker_
.CalledOnValidThread());
325 #if defined(USE_UDEV)
326 if (manufacturer_
.empty()) {
329 *manufacturer
= base::UTF8ToUTF16(manufacturer_
);
332 // This is a non-blocking call as libusb has the descriptor in memory.
333 libusb_device_descriptor desc
;
334 const int rv
= libusb_get_device_descriptor(platform_device_
, &desc
);
335 if (rv
!= LIBUSB_SUCCESS
) {
336 VLOG(1) << "Failed to read device descriptor: "
337 << ConvertPlatformUsbErrorToString(rv
);
341 if (desc
.iManufacturer
== 0) {
345 scoped_refptr
<UsbDeviceHandle
> device_handle
= Open();
346 if (device_handle
.get()) {
347 return device_handle
->GetStringDescriptor(desc
.iManufacturer
, manufacturer
);
353 bool UsbDeviceImpl::GetProduct(base::string16
* product
) {
354 DCHECK(thread_checker_
.CalledOnValidThread());
356 #if defined(USE_UDEV)
357 if (product_
.empty()) {
360 *product
= base::UTF8ToUTF16(product_
);
363 // This is a non-blocking call as libusb has the descriptor in memory.
364 libusb_device_descriptor desc
;
365 const int rv
= libusb_get_device_descriptor(platform_device_
, &desc
);
366 if (rv
!= LIBUSB_SUCCESS
) {
367 VLOG(1) << "Failed to read device descriptor: "
368 << ConvertPlatformUsbErrorToString(rv
);
372 if (desc
.iProduct
== 0) {
376 scoped_refptr
<UsbDeviceHandle
> device_handle
= Open();
377 if (device_handle
.get()) {
378 return device_handle
->GetStringDescriptor(desc
.iProduct
, product
);
384 bool UsbDeviceImpl::GetSerialNumber(base::string16
* serial_number
) {
385 DCHECK(thread_checker_
.CalledOnValidThread());
387 #if defined(USE_UDEV)
388 if (serial_number_
.empty()) {
391 *serial_number
= base::UTF8ToUTF16(serial_number_
);
394 // This is a non-blocking call as libusb has the descriptor in memory.
395 libusb_device_descriptor desc
;
396 const int rv
= libusb_get_device_descriptor(platform_device_
, &desc
);
397 if (rv
!= LIBUSB_SUCCESS
) {
398 VLOG(1) << "Failed to read device descriptor: "
399 << ConvertPlatformUsbErrorToString(rv
);
403 if (desc
.iSerialNumber
== 0) {
407 scoped_refptr
<UsbDeviceHandle
> device_handle
= Open();
408 if (device_handle
.get()) {
409 return device_handle
->GetStringDescriptor(desc
.iSerialNumber
,
416 void UsbDeviceImpl::OnDisconnect() {
417 DCHECK(thread_checker_
.CalledOnValidThread());
418 HandlesVector handles
;
419 swap(handles
, handles_
);
420 for (HandlesVector::iterator it
= handles
.begin(); it
!= handles
.end(); ++it
)
421 (*it
)->InternalClose();
424 } // namespace device