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 #endif // defined(OS_CHROMEOS)
31 UsbEndpointDirection
GetDirection(
32 const libusb_endpoint_descriptor
* descriptor
) {
33 switch (descriptor
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) {
34 case LIBUSB_ENDPOINT_IN
:
35 return USB_DIRECTION_INBOUND
;
36 case LIBUSB_ENDPOINT_OUT
:
37 return USB_DIRECTION_OUTBOUND
;
40 return USB_DIRECTION_INBOUND
;
44 UsbSynchronizationType
GetSynchronizationType(
45 const libusb_endpoint_descriptor
* descriptor
) {
46 switch ((descriptor
->bmAttributes
& LIBUSB_ISO_SYNC_TYPE_MASK
) >> 2) {
47 case LIBUSB_ISO_SYNC_TYPE_NONE
:
48 return USB_SYNCHRONIZATION_NONE
;
49 case LIBUSB_ISO_SYNC_TYPE_ASYNC
:
50 return USB_SYNCHRONIZATION_ASYNCHRONOUS
;
51 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE
:
52 return USB_SYNCHRONIZATION_ADAPTIVE
;
53 case LIBUSB_ISO_SYNC_TYPE_SYNC
:
54 return USB_SYNCHRONIZATION_SYNCHRONOUS
;
57 return USB_SYNCHRONIZATION_NONE
;
61 UsbTransferType
GetTransferType(const libusb_endpoint_descriptor
* descriptor
) {
62 switch (descriptor
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
) {
63 case LIBUSB_TRANSFER_TYPE_CONTROL
:
64 return USB_TRANSFER_CONTROL
;
65 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
:
66 return USB_TRANSFER_ISOCHRONOUS
;
67 case LIBUSB_TRANSFER_TYPE_BULK
:
68 return USB_TRANSFER_BULK
;
69 case LIBUSB_TRANSFER_TYPE_INTERRUPT
:
70 return USB_TRANSFER_INTERRUPT
;
73 return USB_TRANSFER_CONTROL
;
77 UsbUsageType
GetUsageType(const libusb_endpoint_descriptor
* descriptor
) {
78 switch ((descriptor
->bmAttributes
& LIBUSB_ISO_USAGE_TYPE_MASK
) >> 4) {
79 case LIBUSB_ISO_USAGE_TYPE_DATA
:
80 return USB_USAGE_DATA
;
81 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK
:
82 return USB_USAGE_FEEDBACK
;
83 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT
:
84 return USB_USAGE_EXPLICIT_FEEDBACK
;
87 return USB_USAGE_DATA
;
93 UsbDeviceImpl::UsbDeviceImpl(
94 scoped_refptr
<UsbContext
> context
,
95 PlatformUsbDevice platform_device
,
98 const base::string16
& manufacturer_string
,
99 const base::string16
& product_string
,
100 const base::string16
& serial_number
,
101 const std::string
& device_node
,
102 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
)
103 : UsbDevice(vendor_id
,
108 platform_device_(platform_device
),
109 #if defined(OS_CHROMEOS)
110 devnode_(device_node
),
111 #endif // defined(OS_CHROMEOS)
113 task_runner_(base::ThreadTaskRunnerHandle::Get()),
114 blocking_task_runner_(blocking_task_runner
) {
115 CHECK(platform_device
) << "platform_device cannot be NULL";
116 libusb_ref_device(platform_device
);
117 RefreshConfiguration();
120 UsbDeviceImpl::~UsbDeviceImpl() {
121 // The destructor must be safe to call from any thread.
122 libusb_unref_device(platform_device_
);
125 #if defined(OS_CHROMEOS)
127 void UsbDeviceImpl::CheckUsbAccess(const ResultCallback
& callback
) {
128 DCHECK(thread_checker_
.CalledOnValidThread());
129 chromeos::PermissionBrokerClient
* client
=
130 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
131 DCHECK(client
) << "Could not get permission broker client.";
132 client
->CheckPathAccess(devnode_
, callback
);
135 void UsbDeviceImpl::RequestUsbAccess(int interface_id
,
136 const ResultCallback
& callback
) {
137 DCHECK(thread_checker_
.CalledOnValidThread());
138 chromeos::PermissionBrokerClient
* client
=
139 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
140 DCHECK(client
) << "Could not get permission broker client.";
141 client
->RequestPathAccess(devnode_
, interface_id
, callback
);
146 void UsbDeviceImpl::Open(const OpenCallback
& callback
) {
147 DCHECK(thread_checker_
.CalledOnValidThread());
148 blocking_task_runner_
->PostTask(
150 base::Bind(&UsbDeviceImpl::OpenOnBlockingThread
, this, callback
));
153 bool UsbDeviceImpl::Close(scoped_refptr
<UsbDeviceHandle
> handle
) {
154 DCHECK(thread_checker_
.CalledOnValidThread());
156 for (HandlesVector::iterator it
= handles_
.begin(); it
!= handles_
.end();
158 if (it
->get() == handle
.get()) {
159 (*it
)->InternalClose();
167 const UsbConfigDescriptor
* UsbDeviceImpl::GetConfiguration() {
168 DCHECK(thread_checker_
.CalledOnValidThread());
169 return configuration_
.get();
172 void UsbDeviceImpl::OnDisconnect() {
173 DCHECK(thread_checker_
.CalledOnValidThread());
175 // Swap the list of handles into a local variable because closing all open
176 // handles may release the last reference to this object.
177 HandlesVector handles
;
178 swap(handles
, handles_
);
180 for (const scoped_refptr
<UsbDeviceHandleImpl
>& handle
: handles_
) {
181 handle
->InternalClose();
185 void UsbDeviceImpl::RefreshConfiguration() {
186 libusb_config_descriptor
* platform_config
;
188 libusb_get_active_config_descriptor(platform_device_
, &platform_config
);
189 if (rv
!= LIBUSB_SUCCESS
) {
190 USB_LOG(EVENT
) << "Failed to get config descriptor: "
191 << ConvertPlatformUsbErrorToString(rv
);
195 configuration_
.reset(new UsbConfigDescriptor());
196 configuration_
->configuration_value
= platform_config
->bConfigurationValue
;
197 configuration_
->self_powered
= (platform_config
->bmAttributes
& 0x40) != 0;
198 configuration_
->remote_wakeup
= (platform_config
->bmAttributes
& 0x20) != 0;
199 configuration_
->maximum_power
= platform_config
->MaxPower
* 2;
201 for (size_t i
= 0; i
< platform_config
->bNumInterfaces
; ++i
) {
202 const struct libusb_interface
* platform_interface
=
203 &platform_config
->interface
[i
];
204 for (int j
= 0; j
< platform_interface
->num_altsetting
; ++j
) {
205 const struct libusb_interface_descriptor
* platform_alt_setting
=
206 &platform_interface
->altsetting
[j
];
207 UsbInterfaceDescriptor interface
;
209 interface
.interface_number
= platform_alt_setting
->bInterfaceNumber
;
210 interface
.alternate_setting
= platform_alt_setting
->bAlternateSetting
;
211 interface
.interface_class
= platform_alt_setting
->bInterfaceClass
;
212 interface
.interface_subclass
= platform_alt_setting
->bInterfaceSubClass
;
213 interface
.interface_protocol
= platform_alt_setting
->bInterfaceProtocol
;
215 for (size_t k
= 0; k
< platform_alt_setting
->bNumEndpoints
; ++k
) {
216 const struct libusb_endpoint_descriptor
* platform_endpoint
=
217 &platform_alt_setting
->endpoint
[k
];
218 UsbEndpointDescriptor endpoint
;
220 endpoint
.address
= platform_endpoint
->bEndpointAddress
;
221 endpoint
.direction
= GetDirection(platform_endpoint
);
222 endpoint
.maximum_packet_size
= platform_endpoint
->wMaxPacketSize
;
223 endpoint
.synchronization_type
=
224 GetSynchronizationType(platform_endpoint
);
225 endpoint
.transfer_type
= GetTransferType(platform_endpoint
);
226 endpoint
.usage_type
= GetUsageType(platform_endpoint
);
227 endpoint
.polling_interval
= platform_endpoint
->bInterval
;
228 endpoint
.extra_data
= std::vector
<uint8_t>(
229 platform_endpoint
->extra
,
230 platform_endpoint
->extra
+ platform_endpoint
->extra_length
);
232 interface
.endpoints
.push_back(endpoint
);
235 interface
.extra_data
= std::vector
<uint8_t>(
236 platform_alt_setting
->extra
,
237 platform_alt_setting
->extra
+ platform_alt_setting
->extra_length
);
239 configuration_
->interfaces
.push_back(interface
);
243 configuration_
->extra_data
= std::vector
<uint8_t>(
244 platform_config
->extra
,
245 platform_config
->extra
+ platform_config
->extra_length
);
247 libusb_free_config_descriptor(platform_config
);
250 void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback
& callback
) {
251 PlatformUsbDeviceHandle handle
;
252 const int rv
= libusb_open(platform_device_
, &handle
);
253 if (LIBUSB_SUCCESS
== rv
) {
254 task_runner_
->PostTask(
255 FROM_HERE
, base::Bind(&UsbDeviceImpl::Opened
, this, handle
, callback
));
257 USB_LOG(EVENT
) << "Failed to open device: "
258 << ConvertPlatformUsbErrorToString(rv
);
259 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr));
263 void UsbDeviceImpl::Opened(PlatformUsbDeviceHandle platform_handle
,
264 const OpenCallback
& callback
) {
265 DCHECK(thread_checker_
.CalledOnValidThread());
266 scoped_refptr
<UsbDeviceHandleImpl
> device_handle
= new UsbDeviceHandleImpl(
267 context_
, this, platform_handle
, blocking_task_runner_
);
268 handles_
.push_back(device_handle
);
269 callback
.Run(device_handle
);
272 } // namespace device