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/thread_task_runner_handle.h"
14 #include "device/usb/usb_context.h"
15 #include "device/usb/usb_descriptors.h"
16 #include "device/usb/usb_device_handle_impl.h"
17 #include "device/usb/usb_error.h"
18 #include "third_party/libusb/src/libusb/libusb.h"
20 #if defined(OS_CHROMEOS)
21 #include "base/sys_info.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/permission_broker_client.h"
24 #endif // defined(OS_CHROMEOS)
30 #if defined(OS_CHROMEOS)
31 void OnRequestUsbAccessReplied(
32 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
,
33 const base::Callback
<void(bool success
)>& callback
,
35 task_runner
->PostTask(FROM_HERE
, base::Bind(callback
, success
));
37 #endif // defined(OS_CHROMEOS)
39 UsbEndpointDirection
GetDirection(
40 const libusb_endpoint_descriptor
* descriptor
) {
41 switch (descriptor
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) {
42 case LIBUSB_ENDPOINT_IN
:
43 return USB_DIRECTION_INBOUND
;
44 case LIBUSB_ENDPOINT_OUT
:
45 return USB_DIRECTION_OUTBOUND
;
48 return USB_DIRECTION_INBOUND
;
52 UsbSynchronizationType
GetSynchronizationType(
53 const libusb_endpoint_descriptor
* descriptor
) {
54 switch (descriptor
->bmAttributes
& LIBUSB_ISO_SYNC_TYPE_MASK
) {
55 case LIBUSB_ISO_SYNC_TYPE_NONE
:
56 return USB_SYNCHRONIZATION_NONE
;
57 case LIBUSB_ISO_SYNC_TYPE_ASYNC
:
58 return USB_SYNCHRONIZATION_ASYNCHRONOUS
;
59 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE
:
60 return USB_SYNCHRONIZATION_ADAPTIVE
;
61 case LIBUSB_ISO_SYNC_TYPE_SYNC
:
62 return USB_SYNCHRONIZATION_SYNCHRONOUS
;
65 return USB_SYNCHRONIZATION_NONE
;
69 UsbTransferType
GetTransferType(const libusb_endpoint_descriptor
* descriptor
) {
70 switch (descriptor
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
) {
71 case LIBUSB_TRANSFER_TYPE_CONTROL
:
72 return USB_TRANSFER_CONTROL
;
73 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
:
74 return USB_TRANSFER_ISOCHRONOUS
;
75 case LIBUSB_TRANSFER_TYPE_BULK
:
76 return USB_TRANSFER_BULK
;
77 case LIBUSB_TRANSFER_TYPE_INTERRUPT
:
78 return USB_TRANSFER_INTERRUPT
;
81 return USB_TRANSFER_CONTROL
;
85 UsbUsageType
GetUsageType(const libusb_endpoint_descriptor
* descriptor
) {
86 switch (descriptor
->bmAttributes
& LIBUSB_ISO_USAGE_TYPE_MASK
) {
87 case LIBUSB_ISO_USAGE_TYPE_DATA
:
88 return USB_USAGE_DATA
;
89 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK
:
90 return USB_USAGE_FEEDBACK
;
91 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT
:
92 return USB_USAGE_EXPLICIT_FEEDBACK
;
95 return USB_USAGE_DATA
;
101 UsbDevice::UsbDevice(uint16 vendor_id
, uint16 product_id
, uint32 unique_id
)
102 : vendor_id_(vendor_id
), product_id_(product_id
), unique_id_(unique_id
) {
105 UsbDevice::~UsbDevice() {
108 void UsbDevice::NotifyDisconnect() {
109 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnDisconnect(this));
112 UsbDeviceImpl::UsbDeviceImpl(
113 scoped_refptr
<UsbContext
> context
,
114 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
115 PlatformUsbDevice platform_device
,
119 : UsbDevice(vendor_id
, product_id
, unique_id
),
120 platform_device_(platform_device
),
121 current_configuration_cached_(false),
123 ui_task_runner_(ui_task_runner
) {
124 CHECK(platform_device
) << "platform_device cannot be NULL";
125 libusb_ref_device(platform_device
);
128 UsbDeviceImpl::~UsbDeviceImpl() {
129 DCHECK(thread_checker_
.CalledOnValidThread());
130 for (HandlesVector::iterator it
= handles_
.begin(); it
!= handles_
.end();
132 (*it
)->InternalClose();
134 STLClearObject(&handles_
);
135 libusb_unref_device(platform_device_
);
138 #if defined(OS_CHROMEOS)
140 void UsbDeviceImpl::RequestUsbAccess(
142 const base::Callback
<void(bool success
)>& callback
) {
143 DCHECK(thread_checker_
.CalledOnValidThread());
145 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
146 // use permission broker.
147 if (base::SysInfo::IsRunningOnChromeOS()) {
148 chromeos::PermissionBrokerClient
* client
=
149 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
150 DCHECK(client
) << "Could not get permission broker client.";
156 ui_task_runner_
->PostTask(
158 base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess
,
159 base::Unretained(client
),
163 base::Bind(&OnRequestUsbAccessReplied
,
164 base::ThreadTaskRunnerHandle::Get(),
171 scoped_refptr
<UsbDeviceHandle
> UsbDeviceImpl::Open() {
172 DCHECK(thread_checker_
.CalledOnValidThread());
173 PlatformUsbDeviceHandle handle
;
174 const int rv
= libusb_open(platform_device_
, &handle
);
175 if (LIBUSB_SUCCESS
== rv
) {
177 if (!current_configuration_cached_
) {
180 scoped_refptr
<UsbDeviceHandleImpl
> device_handle
=
181 new UsbDeviceHandleImpl(context_
, this, handle
, current_configuration_
);
182 handles_
.push_back(device_handle
);
183 return device_handle
;
185 VLOG(1) << "Failed to open device: " << ConvertPlatformUsbErrorToString(rv
);
190 bool UsbDeviceImpl::Close(scoped_refptr
<UsbDeviceHandle
> handle
) {
191 DCHECK(thread_checker_
.CalledOnValidThread());
193 for (HandlesVector::iterator it
= handles_
.begin(); it
!= handles_
.end();
195 if (it
->get() == handle
.get()) {
196 (*it
)->InternalClose();
204 const UsbConfigDescriptor
& UsbDeviceImpl::GetConfiguration() {
205 DCHECK(thread_checker_
.CalledOnValidThread());
207 if (!current_configuration_cached_
) {
208 libusb_config_descriptor
* platform_config
;
210 libusb_get_active_config_descriptor(platform_device_
, &platform_config
);
211 if (rv
!= LIBUSB_SUCCESS
) {
212 VLOG(1) << "Failed to get config descriptor: "
213 << ConvertPlatformUsbErrorToString(rv
);
214 return current_configuration_
;
217 current_configuration_
.configuration_value
=
218 platform_config
->bConfigurationValue
;
219 current_configuration_
.self_powered
=
220 (platform_config
->bmAttributes
& 0x40) != 0;
221 current_configuration_
.remote_wakeup
=
222 (platform_config
->bmAttributes
& 0x20) != 0;
223 current_configuration_
.maximum_power
= platform_config
->MaxPower
* 2;
225 for (size_t i
= 0; i
< platform_config
->bNumInterfaces
; ++i
) {
226 const struct libusb_interface
* platform_interface
=
227 &platform_config
->interface
[i
];
228 for (int j
= 0; j
< platform_interface
->num_altsetting
; ++j
) {
229 const struct libusb_interface_descriptor
* platform_alt_setting
=
230 &platform_interface
->altsetting
[j
];
231 UsbInterfaceDescriptor interface
;
233 interface
.interface_number
= platform_alt_setting
->bInterfaceNumber
;
234 interface
.alternate_setting
= platform_alt_setting
->bAlternateSetting
;
235 interface
.interface_class
= platform_alt_setting
->bInterfaceClass
;
236 interface
.interface_subclass
= platform_alt_setting
->bInterfaceSubClass
;
237 interface
.interface_protocol
= platform_alt_setting
->bInterfaceProtocol
;
239 for (size_t k
= 0; k
< platform_alt_setting
->bNumEndpoints
; ++k
) {
240 const struct libusb_endpoint_descriptor
* platform_endpoint
=
241 &platform_alt_setting
->endpoint
[k
];
242 UsbEndpointDescriptor endpoint
;
244 endpoint
.address
= platform_endpoint
->bEndpointAddress
;
245 endpoint
.direction
= GetDirection(platform_endpoint
);
246 endpoint
.maximum_packet_size
= platform_endpoint
->wMaxPacketSize
;
247 endpoint
.synchronization_type
=
248 GetSynchronizationType(platform_endpoint
);
249 endpoint
.transfer_type
= GetTransferType(platform_endpoint
);
250 endpoint
.usage_type
= GetUsageType(platform_endpoint
);
251 endpoint
.polling_interval
= platform_endpoint
->bInterval
;
252 endpoint
.extra_data
= std::vector
<uint8_t>(
253 platform_endpoint
->extra
,
254 platform_endpoint
->extra
+ platform_endpoint
->extra_length
);
256 interface
.endpoints
.push_back(endpoint
);
259 interface
.extra_data
= std::vector
<uint8_t>(
260 platform_alt_setting
->extra
,
261 platform_alt_setting
->extra
+ platform_alt_setting
->extra_length
);
263 current_configuration_
.interfaces
.push_back(interface
);
267 current_configuration_
.extra_data
= std::vector
<uint8_t>(
268 platform_config
->extra
,
269 platform_config
->extra
+ platform_config
->extra_length
);
271 libusb_free_config_descriptor(platform_config
);
272 current_configuration_cached_
= true;
275 return current_configuration_
;
278 void UsbDeviceImpl::OnDisconnect() {
279 DCHECK(thread_checker_
.CalledOnValidThread());
280 HandlesVector handles
;
281 swap(handles
, handles_
);
282 for (HandlesVector::iterator it
= handles
.begin(); it
!= handles
.end(); ++it
)
283 (*it
)->InternalClose();
286 } // namespace device