blob: 7a23bff276b404bc0e30b1b058ec03ff8847b72c [file] [log] [blame]
[email protected]b5508682014-04-22 17:10:011// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]1c39a6b2012-04-27 16:09:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
reillyg45919812015-01-22 02:39:595#include "device/usb/usb_service_impl.h"
[email protected]1c39a6b2012-04-27 16:09:576
avi176e2692015-12-22 19:26:527#include <stdint.h>
thakisacd68a22016-04-11 16:12:238
reillyg91fa9952015-06-15 21:47:199#include <list>
thakisacd68a22016-04-11 16:12:2310#include <memory>
[email protected]d165a6442013-08-08 19:38:1111#include <set>
dcheng64f325f2015-12-27 22:05:1012#include <utility>
[email protected]22ac24e2012-10-03 17:56:0513
reillyg91fa9952015-06-15 21:47:1914#include "base/barrier_closure.h"
reillyg0ae3a9992015-01-05 20:12:4215#include "base/bind.h"
reillyg45919812015-01-22 02:39:5916#include "base/location.h"
reillyg257f43092015-01-08 00:48:1017#include "base/memory/weak_ptr.h"
reillyge471fab2014-08-29 01:58:4318#include "base/single_thread_task_runner.h"
[email protected]1c39a6b2012-04-27 16:09:5719#include "base/stl_util.h"
reillygb87cb272015-04-16 19:11:0420#include "base/strings/string_number_conversions.h"
21#include "base/strings/utf_string_conversions.h"
gabc7c963d2016-05-11 21:01:5522#include "base/threading/thread_task_runner_handle.h"
avi176e2692015-12-22 19:26:5223#include "build/build_config.h"
reillyg0f2dc632015-02-23 20:02:0824#include "components/device_event_log/device_event_log.h"
reillyg91fa9952015-06-15 21:47:1925#include "device/usb/usb_device_handle.h"
reillygd77718d2014-09-04 00:57:5626#include "device/usb/usb_error.h"
reillyg6eb7a8a2015-08-06 00:34:0727#include "device/usb/webusb_descriptors.h"
reillyga9de0fa2016-01-28 01:38:0128#include "net/base/io_buffer.h"
reillygb87cb272015-04-16 19:11:0429#include "third_party/libusb/src/libusb/libusb.h"
[email protected]1c39a6b2012-04-27 16:09:5730
reillyg257f43092015-01-08 00:48:1031#if defined(OS_WIN)
reillyg8cbc3ce2015-04-03 07:39:4332#include <setupapi.h>
reillyg257f43092015-01-08 00:48:1033#include <usbiodef.h>
34
reillyg8cbc3ce2015-04-03 07:39:4335#include "base/strings/string_util.h"
juncai0c9eb032015-11-21 05:54:2736#include "device/core/device_info_query_win.h"
reillyg257f43092015-01-08 00:48:1037#endif // OS_WIN
38
reillyg6eb7a8a2015-08-06 00:34:0739using net::IOBufferWithSize;
40
reillygd77718d2014-09-04 00:57:5641namespace device {
[email protected]b5508682014-04-22 17:10:0142
reillyg8cbc3ce2015-04-03 07:39:4343namespace {
44
reillyg6eb7a8a2015-08-06 00:34:0745// Standard USB requests and descriptor types:
46const uint16_t kUsbVersion2_1 = 0x0210;
reillyg6eb7a8a2015-08-06 00:34:0747
reillygb87cb272015-04-16 19:11:0448#if defined(OS_WIN)
49
reillygb87cb272015-04-16 19:11:0450bool IsWinUsbInterface(const std::string& device_path) {
juncai0c9eb032015-11-21 05:54:2751 DeviceInfoQueryWin device_info_query;
52 if (!device_info_query.device_info_list_valid()) {
reillygb87cb272015-04-16 19:11:0453 USB_PLOG(ERROR) << "Failed to create a device information set";
54 return false;
reillyg257f43092015-01-08 00:48:1055 }
56
juncai0c9eb032015-11-21 05:54:2757 // This will add the device so we can query driver info.
58 if (!device_info_query.AddDevice(device_path.c_str())) {
reillygb87cb272015-04-16 19:11:0459 USB_PLOG(ERROR) << "Failed to get device interface data for "
60 << device_path;
61 return false;
reillyg257f43092015-01-08 00:48:1062 }
63
juncai0c9eb032015-11-21 05:54:2764 if (!device_info_query.GetDeviceInfo()) {
reillygb87cb272015-04-16 19:11:0465 USB_PLOG(ERROR) << "Failed to get device info for " << device_path;
66 return false;
67 }
reillygb87cb272015-04-16 19:11:0468
juncai0c9eb032015-11-21 05:54:2769 std::string buffer;
70 if (!device_info_query.GetDeviceStringProperty(SPDRP_SERVICE, &buffer)) {
reillygb87cb272015-04-16 19:11:0471 USB_PLOG(ERROR) << "Failed to get device service property";
72 return false;
73 }
reillyg257f43092015-01-08 00:48:1074
reillygb87cb272015-04-16 19:11:0475 USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << ".";
juncai0c9eb032015-11-21 05:54:2776 if (base::StartsWith(buffer, "WinUSB", base::CompareCase::INSENSITIVE_ASCII))
reillygb87cb272015-04-16 19:11:0477 return true;
reillygb87cb272015-04-16 19:11:0478 return false;
79}
reillyg8cbc3ce2015-04-03 07:39:4380
81#endif // OS_WIN
reillyg257f43092015-01-08 00:48:1082
reillyg91fa9952015-06-15 21:47:1983void GetDeviceListOnBlockingThread(
84 const std::string& new_device_path,
85 scoped_refptr<UsbContext> usb_context,
86 scoped_refptr<base::SequencedTaskRunner> task_runner,
87 base::Callback<void(libusb_device**, size_t)> callback) {
88#if defined(OS_WIN)
89 if (!new_device_path.empty()) {
90 if (!IsWinUsbInterface(new_device_path)) {
91 // Wait to call libusb_get_device_list until libusb will be able to find
92 // a WinUSB interface for the device.
93 task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
94 return;
95 }
96 }
97#endif // defined(OS_WIN)
98
99 libusb_device** platform_devices = NULL;
100 const ssize_t device_count =
101 libusb_get_device_list(usb_context->context(), &platform_devices);
102 if (device_count < 0) {
103 USB_LOG(ERROR) << "Failed to get device list: "
104 << ConvertPlatformUsbErrorToString(device_count);
105 task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
106 return;
107 }
108
109 task_runner->PostTask(FROM_HERE,
110 base::Bind(callback, platform_devices, device_count));
111}
112
reillyg6eb7a8a2015-08-06 00:34:07113void CloseHandleAndRunContinuation(scoped_refptr<UsbDeviceHandle> device_handle,
114 const base::Closure& continuation) {
115 device_handle->Close();
116 continuation.Run();
117}
118
reillyg7446a702016-01-30 01:06:41119void SaveStringsAndRunContinuation(
120 scoped_refptr<UsbDeviceImpl> device,
121 uint8_t manufacturer,
122 uint8_t product,
123 uint8_t serial_number,
reillyg6eb7a8a2015-08-06 00:34:07124 const base::Closure& continuation,
thakisacd68a22016-04-11 16:12:23125 std::unique_ptr<std::map<uint8_t, base::string16>> string_map) {
reillyg7446a702016-01-30 01:06:41126 if (manufacturer != 0)
127 device->set_manufacturer_string((*string_map)[manufacturer]);
128 if (product != 0)
129 device->set_product_string((*string_map)[product]);
130 if (serial_number != 0)
131 device->set_serial_number((*string_map)[serial_number]);
reillyg6eb7a8a2015-08-06 00:34:07132 continuation.Run();
133}
134
reillyg2437acd2016-01-29 01:51:37135void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
136 const base::Closure& barrier,
thakisacd68a22016-04-11 16:12:23137 std::unique_ptr<WebUsbAllowedOrigins> allowed_origins,
reillyg2437acd2016-01-29 01:51:37138 const GURL& landing_page) {
139 scoped_refptr<UsbDeviceImpl> device =
140 static_cast<UsbDeviceImpl*>(device_handle->GetDevice().get());
141
142 if (allowed_origins)
143 device->set_webusb_allowed_origins(std::move(allowed_origins));
144 if (landing_page.is_valid())
145 device->set_webusb_landing_page(landing_page);
146
147 barrier.Run();
148}
149
reillyg6eb7a8a2015-08-06 00:34:07150void OnDeviceOpenedReadDescriptors(
reillyg18b455162015-09-24 02:32:18151 uint8_t manufacturer,
152 uint8_t product,
153 uint8_t serial_number,
reillyg6eb7a8a2015-08-06 00:34:07154 bool read_bos_descriptors,
155 const base::Closure& success_closure,
156 const base::Closure& failure_closure,
157 scoped_refptr<UsbDeviceHandle> device_handle) {
158 if (device_handle) {
thakisacd68a22016-04-11 16:12:23159 std::unique_ptr<std::map<uint8_t, base::string16>> string_map(
reillyg7446a702016-01-30 01:06:41160 new std::map<uint8_t, base::string16>());
reillyg6eb7a8a2015-08-06 00:34:07161 if (manufacturer != 0)
reillyg7446a702016-01-30 01:06:41162 (*string_map)[manufacturer] = base::string16();
reillyg6eb7a8a2015-08-06 00:34:07163 if (product != 0)
reillyg7446a702016-01-30 01:06:41164 (*string_map)[product] = base::string16();
reillyg6eb7a8a2015-08-06 00:34:07165 if (serial_number != 0)
reillyg7446a702016-01-30 01:06:41166 (*string_map)[serial_number] = base::string16();
167
168 int count = 0;
169 if (!string_map->empty())
reillyg6eb7a8a2015-08-06 00:34:07170 count++;
171 if (read_bos_descriptors)
172 count++;
173 DCHECK_GT(count, 0);
174
175 base::Closure barrier =
176 base::BarrierClosure(count, base::Bind(&CloseHandleAndRunContinuation,
177 device_handle, success_closure));
178
reillyg7446a702016-01-30 01:06:41179 if (!string_map->empty()) {
180 scoped_refptr<UsbDeviceImpl> device =
181 static_cast<UsbDeviceImpl*>(device_handle->GetDevice().get());
182
183 ReadUsbStringDescriptors(
184 device_handle, std::move(string_map),
185 base::Bind(&SaveStringsAndRunContinuation, device, manufacturer,
186 product, serial_number, barrier));
reillyg6eb7a8a2015-08-06 00:34:07187 }
188
189 if (read_bos_descriptors) {
reillyg2437acd2016-01-29 01:51:37190 ReadWebUsbDescriptors(device_handle, base::Bind(&OnReadBosDescriptor,
191 device_handle, barrier));
reillyg6eb7a8a2015-08-06 00:34:07192 }
193 } else {
194 failure_closure.Run();
195 }
196}
197
reillygb87cb272015-04-16 19:11:04198} // namespace
199
reillyge471fab2014-08-29 01:58:43200UsbServiceImpl::UsbServiceImpl(
reillygb87cb272015-04-16 19:11:04201 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
reillygb36f8b592016-06-16 08:40:35202 : UsbService(base::ThreadTaskRunnerHandle::Get(), blocking_task_runner),
reillygb87cb272015-04-16 19:11:04203#if defined(OS_WIN)
204 device_observer_(this),
205#endif
reillyg257f43092015-01-08 00:48:10206 weak_factory_(this) {
reillygc4baf412015-08-08 22:51:04207 PlatformUsbContext platform_context = nullptr;
208 int rv = libusb_init(&platform_context);
209 if (rv != LIBUSB_SUCCESS || !platform_context) {
210 USB_LOG(DEBUG) << "Failed to initialize libusb: "
211 << ConvertPlatformUsbErrorToString(rv);
212 return;
213 }
214 context_ = new UsbContext(platform_context);
215
216 rv = libusb_hotplug_register_callback(
reillyg0ae3a9992015-01-05 20:12:42217 context_->context(),
218 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
219 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
reillyg91fa9952015-06-15 21:47:19220 static_cast<libusb_hotplug_flag>(0), LIBUSB_HOTPLUG_MATCH_ANY,
reillyg0ae3a9992015-01-05 20:12:42221 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
222 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
223 if (rv == LIBUSB_SUCCESS) {
224 hotplug_enabled_ = true;
225 }
reillyg91fa9952015-06-15 21:47:19226
reillygef1a7a52015-06-17 16:50:15227 RefreshDevices();
reillyg91fa9952015-06-15 21:47:19228#if defined(OS_WIN)
229 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
230 if (device_monitor) {
231 device_observer_.Add(device_monitor);
232 }
233#endif // OS_WIN
[email protected]e1954872014-04-13 17:43:29234}
235
[email protected]ad2263f2014-05-05 13:57:50236UsbServiceImpl::~UsbServiceImpl() {
reillygb36f8b592016-06-16 08:40:35237 if (hotplug_enabled_)
reillyg0ae3a9992015-01-05 20:12:42238 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
vmpstrb0e145b2016-07-28 02:55:36239 for (auto* platform_device : ignored_devices_)
juncaid23f2ba2016-04-27 23:32:26240 libusb_unref_device(platform_device);
[email protected]22ac24e2012-10-03 17:56:05241}
242
reillygb87cb272015-04-16 19:11:04243void UsbServiceImpl::GetDevices(const GetDevicesCallback& callback) {
[email protected]e1954872014-04-13 17:43:29244 DCHECK(CalledOnValidThread());
[email protected]d165a6442013-08-08 19:38:11245
reillygc4baf412015-08-08 22:51:04246 if (!context_) {
reillygb36f8b592016-06-16 08:40:35247 task_runner()->PostTask(
reillygc4baf412015-08-08 22:51:04248 FROM_HERE,
249 base::Bind(callback, std::vector<scoped_refptr<UsbDevice>>()));
250 return;
251 }
252
reillygef1a7a52015-06-17 16:50:15253 if (hotplug_enabled_ && !enumeration_in_progress_) {
reillygb87cb272015-04-16 19:11:04254 // The device list is updated live when hotplug events are supported.
reillygb36f8b592016-06-16 08:40:35255 UsbService::GetDevices(callback);
reillygb87cb272015-04-16 19:11:04256 } else {
reillyg91fa9952015-06-15 21:47:19257 pending_enumeration_callbacks_.push_back(callback);
reillygef1a7a52015-06-17 16:50:15258 RefreshDevices();
[email protected]22ac24e2012-10-03 17:56:05259 }
[email protected]22ac24e2012-10-03 17:56:05260}
[email protected]b5508682014-04-22 17:10:01261
reillyg8cbc3ce2015-04-03 07:39:43262#if defined(OS_WIN)
reillyg8cbc3ce2015-04-03 07:39:43263
reillygb87cb272015-04-16 19:11:04264void UsbServiceImpl::OnDeviceAdded(const GUID& class_guid,
265 const std::string& device_path) {
266 // Only the root node of a composite USB device has the class GUID
267 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
268 // This first pass filter will catch anything that's sitting on the USB bus
269 // (including devices on 3rd party USB controllers) to avoid the more
270 // expensive driver check that needs to be done on the FILE thread.
271 if (device_path.find("usb") != std::string::npos) {
reillygef1a7a52015-06-17 16:50:15272 pending_path_enumerations_.push(device_path);
273 RefreshDevices();
reillyg8cbc3ce2015-04-03 07:39:43274 }
275}
reillygb87cb272015-04-16 19:11:04276
277void UsbServiceImpl::OnDeviceRemoved(const GUID& class_guid,
278 const std::string& device_path) {
reillygef1a7a52015-06-17 16:50:15279 // The root USB device node is removed last.
reillygb87cb272015-04-16 19:11:04280 if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) {
reillygef1a7a52015-06-17 16:50:15281 RefreshDevices();
reillygb87cb272015-04-16 19:11:04282 }
283}
284
reillyg8cbc3ce2015-04-03 07:39:43285#endif // OS_WIN
286
reillygef1a7a52015-06-17 16:50:15287void UsbServiceImpl::RefreshDevices() {
reillygb87cb272015-04-16 19:11:04288 DCHECK(CalledOnValidThread());
reillygc4baf412015-08-08 22:51:04289 DCHECK(context_);
reillygef1a7a52015-06-17 16:50:15290
291 if (enumeration_in_progress_) {
292 return;
293 }
294
295 enumeration_in_progress_ = true;
reillyg91fa9952015-06-15 21:47:19296 DCHECK(devices_being_enumerated_.empty());
reillygb87cb272015-04-16 19:11:04297
reillygef1a7a52015-06-17 16:50:15298 std::string device_path;
299 if (!pending_path_enumerations_.empty()) {
300 device_path = pending_path_enumerations_.front();
301 pending_path_enumerations_.pop();
reillygb87cb272015-04-16 19:11:04302 }
reillygef1a7a52015-06-17 16:50:15303
reillygb36f8b592016-06-16 08:40:35304 blocking_task_runner()->PostTask(
reillygef1a7a52015-06-17 16:50:15305 FROM_HERE,
306 base::Bind(&GetDeviceListOnBlockingThread, device_path, context_,
reillygb36f8b592016-06-16 08:40:35307 task_runner(), base::Bind(&UsbServiceImpl::OnDeviceList,
308 weak_factory_.GetWeakPtr())));
reillygb87cb272015-04-16 19:11:04309}
310
reillyg91fa9952015-06-15 21:47:19311void UsbServiceImpl::OnDeviceList(libusb_device** platform_devices,
312 size_t device_count) {
313 DCHECK(CalledOnValidThread());
314 if (!platform_devices) {
315 RefreshDevicesComplete();
reillygb87cb272015-04-16 19:11:04316 return;
317 }
318
reillyg91fa9952015-06-15 21:47:19319 base::Closure refresh_complete =
320 base::BarrierClosure(static_cast<int>(device_count),
321 base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
322 weak_factory_.GetWeakPtr()));
323 std::list<PlatformUsbDevice> new_devices;
juncaid23f2ba2016-04-27 23:32:26324 std::set<PlatformUsbDevice> existing_ignored_devices;
reillyg91fa9952015-06-15 21:47:19325
326 // Look for new and existing devices.
327 for (size_t i = 0; i < device_count; ++i) {
reillygb87cb272015-04-16 19:11:04328 PlatformUsbDevice platform_device = platform_devices[i];
juncaid23f2ba2016-04-27 23:32:26329 // Ignore some devices.
skyostil61e1aee22016-08-12 14:12:09330 if (base::ContainsValue(ignored_devices_, platform_device)) {
juncaid23f2ba2016-04-27 23:32:26331 existing_ignored_devices.insert(platform_device);
332 refresh_complete.Run();
333 continue;
334 }
335
reillyg91fa9952015-06-15 21:47:19336 auto it = platform_devices_.find(platform_device);
337
338 if (it == platform_devices_.end()) {
reillyg91fa9952015-06-15 21:47:19339 new_devices.push_back(platform_device);
340 } else {
341 it->second->set_visited(true);
342 refresh_complete.Run();
reillygb87cb272015-04-16 19:11:04343 }
344 }
345
reillyg91fa9952015-06-15 21:47:19346 // Remove devices not seen in this enumeration.
347 for (PlatformDeviceMap::iterator it = platform_devices_.begin();
348 it != platform_devices_.end();
349 /* incremented internally */) {
350 PlatformDeviceMap::iterator current = it++;
351 const scoped_refptr<UsbDeviceImpl>& device = current->second;
352 if (device->was_visited()) {
353 device->set_visited(false);
354 } else {
355 RemoveDevice(device);
356 }
357 }
358
juncaid23f2ba2016-04-27 23:32:26359 // Remove devices not seen in this enumeration from |ignored_devices_|.
360 for (auto it = ignored_devices_.begin(); it != ignored_devices_.end();
361 /* incremented internally */) {
362 auto current = it++;
skyostil61e1aee22016-08-12 14:12:09363 if (!base::ContainsValue(existing_ignored_devices, *current)) {
juncaid23f2ba2016-04-27 23:32:26364 libusb_unref_device(*current);
365 ignored_devices_.erase(current);
366 }
367 }
368
reillyg91fa9952015-06-15 21:47:19369 for (PlatformUsbDevice platform_device : new_devices) {
370 EnumerateDevice(platform_device, refresh_complete);
371 }
372
373 libusb_free_device_list(platform_devices, true);
reillygb87cb272015-04-16 19:11:04374}
375
reillyg91fa9952015-06-15 21:47:19376void UsbServiceImpl::RefreshDevicesComplete() {
reillygef1a7a52015-06-17 16:50:15377 DCHECK(CalledOnValidThread());
378 DCHECK(enumeration_in_progress_);
379
reillygb87cb272015-04-16 19:11:04380 enumeration_ready_ = true;
reillygef1a7a52015-06-17 16:50:15381 enumeration_in_progress_ = false;
382 devices_being_enumerated_.clear();
reillygb87cb272015-04-16 19:11:04383
reillyg91fa9952015-06-15 21:47:19384 if (!pending_enumeration_callbacks_.empty()) {
reillygb36f8b592016-06-16 08:40:35385 std::vector<scoped_refptr<UsbDevice>> result;
386 result.reserve(devices().size());
387 for (const auto& map_entry : devices())
388 result.push_back(map_entry.second);
reillygb87cb272015-04-16 19:11:04389
reillyg91fa9952015-06-15 21:47:19390 std::vector<GetDevicesCallback> callbacks;
391 callbacks.swap(pending_enumeration_callbacks_);
reillygb36f8b592016-06-16 08:40:35392 for (const GetDevicesCallback& callback : callbacks)
393 callback.Run(result);
reillygb87cb272015-04-16 19:11:04394 }
reillyg91fa9952015-06-15 21:47:19395
396 if (!pending_path_enumerations_.empty()) {
reillygef1a7a52015-06-17 16:50:15397 RefreshDevices();
reillyg91fa9952015-06-15 21:47:19398 }
reillygb87cb272015-04-16 19:11:04399}
400
reillyg91fa9952015-06-15 21:47:19401void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device,
402 const base::Closure& refresh_complete) {
reillygc4baf412015-08-08 22:51:04403 DCHECK(context_);
reillyg91fa9952015-06-15 21:47:19404 devices_being_enumerated_.insert(platform_device);
reillygb87cb272015-04-16 19:11:04405
reillyg91fa9952015-06-15 21:47:19406 libusb_device_descriptor descriptor;
407 int rv = libusb_get_device_descriptor(platform_device, &descriptor);
408 if (rv == LIBUSB_SUCCESS) {
reillyg8fe5eaba2016-04-05 21:34:12409 if (descriptor.bDeviceClass == LIBUSB_CLASS_HUB) {
410 // Don't try to enumerate hubs. We never want to connect to a hub.
juncaid23f2ba2016-04-27 23:32:26411 libusb_ref_device(platform_device);
412 ignored_devices_.insert(platform_device);
reillyg8fe5eaba2016-04-05 21:34:12413 refresh_complete.Run();
414 return;
415 }
416
reillyga8a7407b2016-04-07 02:20:29417 scoped_refptr<UsbDeviceImpl> device(new UsbDeviceImpl(
reillygb36f8b592016-06-16 08:40:35418 context_, platform_device, descriptor, blocking_task_runner()));
reillyg91fa9952015-06-15 21:47:19419 base::Closure add_device =
420 base::Bind(&UsbServiceImpl::AddDevice, weak_factory_.GetWeakPtr(),
421 refresh_complete, device);
juncaid23f2ba2016-04-27 23:32:26422 base::Closure enumeration_failed = base::Bind(
423 &UsbServiceImpl::EnumerationFailed, weak_factory_.GetWeakPtr(),
424 platform_device, refresh_complete);
reillyg6eb7a8a2015-08-06 00:34:07425 bool read_bos_descriptors = descriptor.bcdUSB >= kUsbVersion2_1;
reillyg91fa9952015-06-15 21:47:19426
reillyg91fa9952015-06-15 21:47:19427 if (descriptor.iManufacturer == 0 && descriptor.iProduct == 0 &&
reillyg6eb7a8a2015-08-06 00:34:07428 descriptor.iSerialNumber == 0 && !read_bos_descriptors) {
429 // Don't bother disturbing the device if it has no descriptors to offer.
reillyg91fa9952015-06-15 21:47:19430 add_device.Run();
431 } else {
reillyg6eb7a8a2015-08-06 00:34:07432 device->Open(base::Bind(&OnDeviceOpenedReadDescriptors,
433 descriptor.iManufacturer, descriptor.iProduct,
434 descriptor.iSerialNumber, read_bos_descriptors,
juncaid23f2ba2016-04-27 23:32:26435 add_device, enumeration_failed));
reillyg91fa9952015-06-15 21:47:19436 }
reillyg91fa9952015-06-15 21:47:19437 } else {
438 USB_LOG(EVENT) << "Failed to get device descriptor: "
439 << ConvertPlatformUsbErrorToString(rv);
440 refresh_complete.Run();
441 }
442}
443
444void UsbServiceImpl::AddDevice(const base::Closure& refresh_complete,
445 scoped_refptr<UsbDeviceImpl> device) {
446 auto it = devices_being_enumerated_.find(device->platform_device());
447 if (it == devices_being_enumerated_.end()) {
448 // Device was removed while being enumerated.
449 refresh_complete.Run();
450 return;
451 }
reillyg91fa9952015-06-15 21:47:19452
453 platform_devices_[device->platform_device()] = device;
skyostil61e1aee22016-08-12 14:12:09454 DCHECK(!base::ContainsKey(devices(), device->guid()));
reillygb36f8b592016-06-16 08:40:35455 devices()[device->guid()] = device;
reillygb87cb272015-04-16 19:11:04456
457 USB_LOG(USER) << "USB device added: vendor=" << device->vendor_id() << " \""
458 << device->manufacturer_string()
459 << "\", product=" << device->product_id() << " \""
460 << device->product_string() << "\", serial=\""
rockotdfbc94d1d2015-06-01 20:53:09461 << device->serial_number() << "\", guid=" << device->guid();
reillygb87cb272015-04-16 19:11:04462
463 if (enumeration_ready_) {
464 NotifyDeviceAdded(device);
465 }
466
reillyg91fa9952015-06-15 21:47:19467 refresh_complete.Run();
reillygb87cb272015-04-16 19:11:04468}
469
470void UsbServiceImpl::RemoveDevice(scoped_refptr<UsbDeviceImpl> device) {
471 platform_devices_.erase(device->platform_device());
reillygb36f8b592016-06-16 08:40:35472 devices().erase(device->guid());
reillygb87cb272015-04-16 19:11:04473
rockotdfbc94d1d2015-06-01 20:53:09474 USB_LOG(USER) << "USB device removed: guid=" << device->guid();
reillygb87cb272015-04-16 19:11:04475
476 NotifyDeviceRemoved(device);
477 device->OnDisconnect();
478}
479
reillyg0ae3a9992015-01-05 20:12:42480// static
481int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
482 PlatformUsbDevice device,
483 libusb_hotplug_event event,
484 void* user_data) {
485 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
486 // around registering, deregistering and calling hotplug callback functions
487 // and so guarantees that this function will not be called by the event
488 // processing thread after it has been deregistered.
489 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data);
490 switch (event) {
491 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
reillygb87cb272015-04-16 19:11:04492 libusb_ref_device(device); // Released in OnPlatformDeviceAdded.
reillygb36f8b592016-06-16 08:40:35493 if (self->task_runner()->BelongsToCurrentThread()) {
reillygb87cb272015-04-16 19:11:04494 self->OnPlatformDeviceAdded(device);
reillyg0ae3a9992015-01-05 20:12:42495 } else {
reillygb36f8b592016-06-16 08:40:35496 self->task_runner()->PostTask(
reillygb87cb272015-04-16 19:11:04497 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded,
reillyg0ae3a9992015-01-05 20:12:42498 base::Unretained(self), device));
499 }
500 break;
501 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
reillygb87cb272015-04-16 19:11:04502 libusb_ref_device(device); // Released in OnPlatformDeviceRemoved.
reillygb36f8b592016-06-16 08:40:35503 if (self->task_runner()->BelongsToCurrentThread()) {
reillygb87cb272015-04-16 19:11:04504 self->OnPlatformDeviceRemoved(device);
reillyg0ae3a9992015-01-05 20:12:42505 } else {
reillygb36f8b592016-06-16 08:40:35506 self->task_runner()->PostTask(
reillygb87cb272015-04-16 19:11:04507 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved,
reillyg0ae3a9992015-01-05 20:12:42508 base::Unretained(self), device));
509 }
510 break;
511 default:
512 NOTREACHED();
513 }
514
515 return 0;
516}
517
reillygb87cb272015-04-16 19:11:04518void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device) {
reillyg0ae3a9992015-01-05 20:12:42519 DCHECK(CalledOnValidThread());
skyostil61e1aee22016-08-12 14:12:09520 DCHECK(!base::ContainsKey(platform_devices_, platform_device));
reillyg91fa9952015-06-15 21:47:19521 EnumerateDevice(platform_device, base::Bind(&base::DoNothing));
522 libusb_unref_device(platform_device);
reillyg0ae3a9992015-01-05 20:12:42523}
524
reillygb87cb272015-04-16 19:11:04525void UsbServiceImpl::OnPlatformDeviceRemoved(
526 PlatformUsbDevice platform_device) {
reillyg0ae3a9992015-01-05 20:12:42527 DCHECK(CalledOnValidThread());
reillyg0ae3a9992015-01-05 20:12:42528 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device);
529 if (it != platform_devices_.end()) {
reillyg91fa9952015-06-15 21:47:19530 RemoveDevice(it->second);
reillyg0ae3a9992015-01-05 20:12:42531 } else {
reillyg91fa9952015-06-15 21:47:19532 devices_being_enumerated_.erase(platform_device);
reillyg0ae3a9992015-01-05 20:12:42533 }
reillyg0ae3a9992015-01-05 20:12:42534 libusb_unref_device(platform_device);
535}
536
juncaid23f2ba2016-04-27 23:32:26537void UsbServiceImpl::EnumerationFailed(PlatformUsbDevice platform_device,
538 const base::Closure& refresh_complete) {
539 libusb_ref_device(platform_device);
540 ignored_devices_.insert(platform_device);
541 refresh_complete.Run();
542}
543
reillygd77718d2014-09-04 00:57:56544} // namespace device