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/sequenced_task_runner.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "components/device_event_log/device_event_log.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 "chromeos/dbus/dbus_thread_manager.h"
24 #include "chromeos/dbus/permission_broker_client.h"
25 #include "dbus/file_descriptor.h"
26 #endif // defined(OS_CHROMEOS)
32 UsbEndpointDirection
GetDirection(
33 const libusb_endpoint_descriptor
* descriptor
) {
34 switch (descriptor
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) {
35 case LIBUSB_ENDPOINT_IN
:
36 return USB_DIRECTION_INBOUND
;
37 case LIBUSB_ENDPOINT_OUT
:
38 return USB_DIRECTION_OUTBOUND
;
41 return USB_DIRECTION_INBOUND
;
45 UsbSynchronizationType
GetSynchronizationType(
46 const libusb_endpoint_descriptor
* descriptor
) {
47 switch ((descriptor
->bmAttributes
& LIBUSB_ISO_SYNC_TYPE_MASK
) >> 2) {
48 case LIBUSB_ISO_SYNC_TYPE_NONE
:
49 return USB_SYNCHRONIZATION_NONE
;
50 case LIBUSB_ISO_SYNC_TYPE_ASYNC
:
51 return USB_SYNCHRONIZATION_ASYNCHRONOUS
;
52 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE
:
53 return USB_SYNCHRONIZATION_ADAPTIVE
;
54 case LIBUSB_ISO_SYNC_TYPE_SYNC
:
55 return USB_SYNCHRONIZATION_SYNCHRONOUS
;
58 return USB_SYNCHRONIZATION_NONE
;
62 UsbTransferType
GetTransferType(const libusb_endpoint_descriptor
* descriptor
) {
63 switch (descriptor
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
) {
64 case LIBUSB_TRANSFER_TYPE_CONTROL
:
65 return USB_TRANSFER_CONTROL
;
66 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
:
67 return USB_TRANSFER_ISOCHRONOUS
;
68 case LIBUSB_TRANSFER_TYPE_BULK
:
69 return USB_TRANSFER_BULK
;
70 case LIBUSB_TRANSFER_TYPE_INTERRUPT
:
71 return USB_TRANSFER_INTERRUPT
;
74 return USB_TRANSFER_CONTROL
;
78 UsbUsageType
GetUsageType(const libusb_endpoint_descriptor
* descriptor
) {
79 switch ((descriptor
->bmAttributes
& LIBUSB_ISO_USAGE_TYPE_MASK
) >> 4) {
80 case LIBUSB_ISO_USAGE_TYPE_DATA
:
81 return USB_USAGE_DATA
;
82 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK
:
83 return USB_USAGE_FEEDBACK
;
84 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT
:
85 return USB_USAGE_EXPLICIT_FEEDBACK
;
88 return USB_USAGE_DATA
;
92 void ConvertConfigDescriptor(const libusb_config_descriptor
* platform_config
,
93 UsbConfigDescriptor
* configuration
) {
94 configuration
->configuration_value
= platform_config
->bConfigurationValue
;
95 configuration
->self_powered
= (platform_config
->bmAttributes
& 0x40) != 0;
96 configuration
->remote_wakeup
= (platform_config
->bmAttributes
& 0x20) != 0;
97 configuration
->maximum_power
= platform_config
->MaxPower
* 2;
99 for (size_t i
= 0; i
< platform_config
->bNumInterfaces
; ++i
) {
100 const struct libusb_interface
* platform_interface
=
101 &platform_config
->interface
[i
];
102 for (int j
= 0; j
< platform_interface
->num_altsetting
; ++j
) {
103 const struct libusb_interface_descriptor
* platform_alt_setting
=
104 &platform_interface
->altsetting
[j
];
105 UsbInterfaceDescriptor interface
;
107 interface
.interface_number
= platform_alt_setting
->bInterfaceNumber
;
108 interface
.alternate_setting
= platform_alt_setting
->bAlternateSetting
;
109 interface
.interface_class
= platform_alt_setting
->bInterfaceClass
;
110 interface
.interface_subclass
= platform_alt_setting
->bInterfaceSubClass
;
111 interface
.interface_protocol
= platform_alt_setting
->bInterfaceProtocol
;
113 interface
.endpoints
.reserve(platform_alt_setting
->bNumEndpoints
);
114 for (size_t k
= 0; k
< platform_alt_setting
->bNumEndpoints
; ++k
) {
115 const struct libusb_endpoint_descriptor
* platform_endpoint
=
116 &platform_alt_setting
->endpoint
[k
];
117 UsbEndpointDescriptor endpoint
;
119 endpoint
.address
= platform_endpoint
->bEndpointAddress
;
120 endpoint
.direction
= GetDirection(platform_endpoint
);
121 endpoint
.maximum_packet_size
= platform_endpoint
->wMaxPacketSize
;
122 endpoint
.synchronization_type
=
123 GetSynchronizationType(platform_endpoint
);
124 endpoint
.transfer_type
= GetTransferType(platform_endpoint
);
125 endpoint
.usage_type
= GetUsageType(platform_endpoint
);
126 endpoint
.polling_interval
= platform_endpoint
->bInterval
;
127 endpoint
.extra_data
= std::vector
<uint8_t>(
128 platform_endpoint
->extra
,
129 platform_endpoint
->extra
+ platform_endpoint
->extra_length
);
131 interface
.endpoints
.push_back(endpoint
);
134 interface
.extra_data
= std::vector
<uint8_t>(
135 platform_alt_setting
->extra
,
136 platform_alt_setting
->extra
+ platform_alt_setting
->extra_length
);
138 configuration
->interfaces
.push_back(interface
);
142 configuration
->extra_data
= std::vector
<uint8_t>(
143 platform_config
->extra
,
144 platform_config
->extra
+ platform_config
->extra_length
);
149 UsbDeviceImpl::UsbDeviceImpl(
150 scoped_refptr
<UsbContext
> context
,
151 PlatformUsbDevice platform_device
,
154 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
)
155 : UsbDevice(vendor_id
,
160 platform_device_(platform_device
),
162 task_runner_(base::ThreadTaskRunnerHandle::Get()),
163 blocking_task_runner_(blocking_task_runner
) {
164 CHECK(platform_device
) << "platform_device cannot be NULL";
165 libusb_ref_device(platform_device
);
166 ReadAllConfigurations();
167 RefreshActiveConfiguration();
170 UsbDeviceImpl::~UsbDeviceImpl() {
171 // The destructor must be safe to call from any thread.
172 libusb_unref_device(platform_device_
);
175 #if defined(OS_CHROMEOS)
177 void UsbDeviceImpl::CheckUsbAccess(const ResultCallback
& callback
) {
178 DCHECK(thread_checker_
.CalledOnValidThread());
179 chromeos::PermissionBrokerClient
* client
=
180 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
181 DCHECK(client
) << "Could not get permission broker client.";
182 client
->CheckPathAccess(device_path_
, callback
);
185 #endif // defined(OS_CHROMEOS)
187 void UsbDeviceImpl::Open(const OpenCallback
& callback
) {
188 DCHECK(thread_checker_
.CalledOnValidThread());
190 #if defined(OS_CHROMEOS)
191 chromeos::PermissionBrokerClient
* client
=
192 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
193 DCHECK(client
) << "Could not get permission broker client.";
196 base::Bind(&UsbDeviceImpl::OnOpenRequestComplete
, this, callback
));
198 blocking_task_runner_
->PostTask(
200 base::Bind(&UsbDeviceImpl::OpenOnBlockingThread
, this, callback
));
201 #endif // defined(OS_CHROMEOS)
204 bool UsbDeviceImpl::Close(scoped_refptr
<UsbDeviceHandle
> handle
) {
205 DCHECK(thread_checker_
.CalledOnValidThread());
207 for (HandlesVector::iterator it
= handles_
.begin(); it
!= handles_
.end();
209 if (it
->get() == handle
.get()) {
210 (*it
)->InternalClose();
218 const UsbConfigDescriptor
* UsbDeviceImpl::GetActiveConfiguration() {
219 DCHECK(thread_checker_
.CalledOnValidThread());
220 return active_configuration_
;
223 void UsbDeviceImpl::OnDisconnect() {
224 DCHECK(thread_checker_
.CalledOnValidThread());
226 // Swap the list of handles into a local variable because closing all open
227 // handles may release the last reference to this object.
228 HandlesVector handles
;
229 swap(handles
, handles_
);
231 for (const scoped_refptr
<UsbDeviceHandleImpl
>& handle
: handles_
) {
232 handle
->InternalClose();
236 void UsbDeviceImpl::ReadAllConfigurations() {
237 libusb_device_descriptor device_descriptor
;
238 int rv
= libusb_get_device_descriptor(platform_device_
, &device_descriptor
);
239 if (rv
== LIBUSB_SUCCESS
) {
240 uint8_t num_configurations
= device_descriptor
.bNumConfigurations
;
241 configurations_
.reserve(num_configurations
);
242 for (uint8_t i
= 0; i
< num_configurations
; ++i
) {
243 libusb_config_descriptor
* platform_config
;
244 rv
= libusb_get_config_descriptor(platform_device_
, i
, &platform_config
);
245 if (rv
!= LIBUSB_SUCCESS
) {
246 USB_LOG(EVENT
) << "Failed to get config descriptor: "
247 << ConvertPlatformUsbErrorToString(rv
);
251 UsbConfigDescriptor config_descriptor
;
252 ConvertConfigDescriptor(platform_config
, &config_descriptor
);
253 configurations_
.push_back(config_descriptor
);
254 libusb_free_config_descriptor(platform_config
);
257 USB_LOG(EVENT
) << "Failed to get device descriptor: "
258 << ConvertPlatformUsbErrorToString(rv
);
262 void UsbDeviceImpl::RefreshActiveConfiguration() {
263 active_configuration_
= nullptr;
264 libusb_config_descriptor
* platform_config
;
266 libusb_get_active_config_descriptor(platform_device_
, &platform_config
);
267 if (rv
!= LIBUSB_SUCCESS
) {
268 USB_LOG(EVENT
) << "Failed to get config descriptor: "
269 << ConvertPlatformUsbErrorToString(rv
);
273 for (const auto& config
: configurations_
) {
274 if (config
.configuration_value
== platform_config
->bConfigurationValue
) {
275 active_configuration_
= &config
;
280 libusb_free_config_descriptor(platform_config
);
283 #if defined(OS_CHROMEOS)
285 void UsbDeviceImpl::OnOpenRequestComplete(const OpenCallback
& callback
,
286 dbus::FileDescriptor fd
) {
287 blocking_task_runner_
->PostTask(
288 FROM_HERE
, base::Bind(&UsbDeviceImpl::OpenOnBlockingThreadWithFd
, this,
289 base::Passed(&fd
), callback
));
292 void UsbDeviceImpl::OpenOnBlockingThreadWithFd(dbus::FileDescriptor fd
,
293 const OpenCallback
& callback
) {
295 if (!fd
.is_valid()) {
296 USB_LOG(EVENT
) << "Did not get valid device handle from permission broker.";
297 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr));
301 PlatformUsbDeviceHandle handle
;
302 const int rv
= libusb_open_fd(platform_device_
, fd
.TakeValue(), &handle
);
303 if (LIBUSB_SUCCESS
== rv
) {
304 task_runner_
->PostTask(
305 FROM_HERE
, base::Bind(&UsbDeviceImpl::Opened
, this, handle
, callback
));
307 USB_LOG(EVENT
) << "Failed to open device: "
308 << ConvertPlatformUsbErrorToString(rv
);
309 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr));
313 #endif // defined(OS_CHROMEOS)
315 void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback
& callback
) {
316 PlatformUsbDeviceHandle handle
;
317 const int rv
= libusb_open(platform_device_
, &handle
);
318 if (LIBUSB_SUCCESS
== rv
) {
319 task_runner_
->PostTask(
320 FROM_HERE
, base::Bind(&UsbDeviceImpl::Opened
, this, handle
, callback
));
322 USB_LOG(EVENT
) << "Failed to open device: "
323 << ConvertPlatformUsbErrorToString(rv
);
324 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr));
328 void UsbDeviceImpl::Opened(PlatformUsbDeviceHandle platform_handle
,
329 const OpenCallback
& callback
) {
330 DCHECK(thread_checker_
.CalledOnValidThread());
331 scoped_refptr
<UsbDeviceHandleImpl
> device_handle
= new UsbDeviceHandleImpl(
332 context_
, this, platform_handle
, blocking_task_runner_
);
333 handles_
.push_back(device_handle
);
334 callback
.Run(device_handle
);
337 } // namespace device