blob: ea7ad7f498108d213619935c2de2ddbb107b6fa1 [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
reillygb87cb272015-04-16 19:11:047#include <algorithm>
reillyg91fa9952015-06-15 21:47:198#include <list>
[email protected]d165a6442013-08-08 19:38:119#include <set>
[email protected]22ac24e2012-10-03 17:56:0510
reillyg91fa9952015-06-15 21:47:1911#include "base/barrier_closure.h"
reillyg0ae3a9992015-01-05 20:12:4212#include "base/bind.h"
reillyg45919812015-01-22 02:39:5913#include "base/location.h"
reillyg257f43092015-01-08 00:48:1014#include "base/memory/weak_ptr.h"
reillyge471fab2014-08-29 01:58:4315#include "base/single_thread_task_runner.h"
[email protected]1c39a6b2012-04-27 16:09:5716#include "base/stl_util.h"
reillygb87cb272015-04-16 19:11:0417#include "base/strings/string_number_conversions.h"
18#include "base/strings/utf_string_conversions.h"
reillyg0ae3a9992015-01-05 20:12:4219#include "base/thread_task_runner_handle.h"
reillyg0f2dc632015-02-23 20:02:0820#include "components/device_event_log/device_event_log.h"
reillyg91fa9952015-06-15 21:47:1921#include "device/usb/usb_device_handle.h"
reillygd77718d2014-09-04 00:57:5622#include "device/usb/usb_error.h"
reillygb87cb272015-04-16 19:11:0423#include "third_party/libusb/src/libusb/libusb.h"
[email protected]1c39a6b2012-04-27 16:09:5724
reillyg257f43092015-01-08 00:48:1025#if defined(OS_WIN)
reillyg8cbc3ce2015-04-03 07:39:4326#include <setupapi.h>
reillyg257f43092015-01-08 00:48:1027#include <usbiodef.h>
28
reillyg8cbc3ce2015-04-03 07:39:4329#include "base/strings/string_util.h"
reillyg257f43092015-01-08 00:48:1030#endif // OS_WIN
31
reillygb87cb272015-04-16 19:11:0432#if defined(USE_UDEV)
33#include "device/udev_linux/scoped_udev.h"
34#endif // USE_UDEV
35
reillygd77718d2014-09-04 00:57:5636namespace device {
[email protected]b5508682014-04-22 17:10:0137
reillyg8cbc3ce2015-04-03 07:39:4338namespace {
39
reillygb87cb272015-04-16 19:11:0440#if defined(OS_WIN)
41
reillyg8cbc3ce2015-04-03 07:39:4342// Wrapper around a HDEVINFO that automatically destroys it.
43class ScopedDeviceInfoList {
44 public:
45 explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {}
46
47 ~ScopedDeviceInfoList() {
48 if (valid()) {
49 SetupDiDestroyDeviceInfoList(handle_);
50 }
51 }
52
53 bool valid() { return handle_ != INVALID_HANDLE_VALUE; }
54
55 HDEVINFO get() { return handle_; }
56
57 private:
58 HDEVINFO handle_;
59
60 DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList);
61};
62
63// Wrapper around an SP_DEVINFO_DATA that initializes it properly and
64// automatically deletes it.
65class ScopedDeviceInfo {
66 public:
67 ScopedDeviceInfo() {
68 memset(&dev_info_data_, 0, sizeof(dev_info_data_));
69 dev_info_data_.cbSize = sizeof(dev_info_data_);
70 }
71
72 ~ScopedDeviceInfo() {
73 if (dev_info_set_ != INVALID_HANDLE_VALUE) {
74 SetupDiDeleteDeviceInfo(dev_info_set_, &dev_info_data_);
75 }
76 }
77
78 // Once the SP_DEVINFO_DATA has been populated it must be freed using the
79 // HDEVINFO it was created from.
80 void set_valid(HDEVINFO dev_info_set) {
81 DCHECK(dev_info_set_ == INVALID_HANDLE_VALUE);
82 DCHECK(dev_info_set != INVALID_HANDLE_VALUE);
83 dev_info_set_ = dev_info_set;
84 }
85
86 PSP_DEVINFO_DATA get() { return &dev_info_data_; }
87
88 private:
89 HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE;
90 SP_DEVINFO_DATA dev_info_data_;
91};
92
reillygb87cb272015-04-16 19:11:0493bool IsWinUsbInterface(const std::string& device_path) {
94 ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL));
95 if (!dev_info_list.valid()) {
96 USB_PLOG(ERROR) << "Failed to create a device information set";
97 return false;
reillyg257f43092015-01-08 00:48:1098 }
99
reillygb87cb272015-04-16 19:11:04100 // This will add the device to |dev_info_list| so we can query driver info.
101 if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0,
102 NULL)) {
103 USB_PLOG(ERROR) << "Failed to get device interface data for "
104 << device_path;
105 return false;
reillyg257f43092015-01-08 00:48:10106 }
107
reillygb87cb272015-04-16 19:11:04108 ScopedDeviceInfo dev_info;
109 if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) {
110 USB_PLOG(ERROR) << "Failed to get device info for " << device_path;
111 return false;
112 }
113 dev_info.set_valid(dev_info_list.get());
114
115 DWORD reg_data_type;
116 BYTE buffer[256];
117 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(),
118 SPDRP_SERVICE, &reg_data_type,
119 &buffer[0], sizeof buffer, NULL)) {
120 USB_PLOG(ERROR) << "Failed to get device service property";
121 return false;
122 }
123 if (reg_data_type != REG_SZ) {
124 USB_LOG(ERROR) << "Unexpected data type for driver service: "
125 << reg_data_type;
126 return false;
reillyg257f43092015-01-08 00:48:10127 }
128
reillygb87cb272015-04-16 19:11:04129 USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << ".";
130 if (base::strncasecmp("WinUSB", (const char*)&buffer[0], sizeof "WinUSB") ==
131 0) {
132 return true;
133 }
134 return false;
135}
reillyg8cbc3ce2015-04-03 07:39:43136
137#endif // OS_WIN
reillyg257f43092015-01-08 00:48:10138
reillyg91fa9952015-06-15 21:47:19139void GetDeviceListOnBlockingThread(
140 const std::string& new_device_path,
141 scoped_refptr<UsbContext> usb_context,
142 scoped_refptr<base::SequencedTaskRunner> task_runner,
143 base::Callback<void(libusb_device**, size_t)> callback) {
144#if defined(OS_WIN)
145 if (!new_device_path.empty()) {
146 if (!IsWinUsbInterface(new_device_path)) {
147 // Wait to call libusb_get_device_list until libusb will be able to find
148 // a WinUSB interface for the device.
149 task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
150 return;
151 }
152 }
153#endif // defined(OS_WIN)
154
155 libusb_device** platform_devices = NULL;
156 const ssize_t device_count =
157 libusb_get_device_list(usb_context->context(), &platform_devices);
158 if (device_count < 0) {
159 USB_LOG(ERROR) << "Failed to get device list: "
160 << ConvertPlatformUsbErrorToString(device_count);
161 task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
162 return;
163 }
164
165 task_runner->PostTask(FROM_HERE,
166 base::Bind(callback, platform_devices, device_count));
167}
168
169#if defined(USE_UDEV)
170
171void EnumerateUdevDevice(scoped_refptr<UsbDeviceImpl> device,
172 scoped_refptr<base::SequencedTaskRunner> task_runner,
173 const base::Closure& success_closure,
174 const base::Closure& failure_closure) {
175 ScopedUdevPtr udev(udev_new());
176 ScopedUdevEnumeratePtr udev_enumerate(udev_enumerate_new(udev.get()));
177
178 udev_enumerate_add_match_subsystem(udev_enumerate.get(), "usb");
179 if (udev_enumerate_scan_devices(udev_enumerate.get()) != 0) {
180 task_runner->PostTask(FROM_HERE, failure_closure);
reillyg5fcec062015-06-17 00:44:24181 return;
reillyg91fa9952015-06-15 21:47:19182 }
183
184 std::string bus_number =
185 base::IntToString(libusb_get_bus_number(device->platform_device()));
186 std::string device_address =
187 base::IntToString(libusb_get_device_address(device->platform_device()));
188 udev_list_entry* devices =
189 udev_enumerate_get_list_entry(udev_enumerate.get());
190 for (udev_list_entry* i = devices; i != NULL;
191 i = udev_list_entry_get_next(i)) {
192 ScopedUdevDevicePtr udev_device(
193 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
194 if (udev_device) {
195 const char* value =
196 udev_device_get_sysattr_value(udev_device.get(), "busnum");
197 if (!value || bus_number != value) {
198 continue;
199 }
200 value = udev_device_get_sysattr_value(udev_device.get(), "devnum");
201 if (!value || device_address != value) {
202 continue;
203 }
204
205 value = udev_device_get_sysattr_value(udev_device.get(), "manufacturer");
206 if (value) {
207 device->set_manufacturer_string(base::UTF8ToUTF16(value));
208 }
209 value = udev_device_get_sysattr_value(udev_device.get(), "product");
210 if (value) {
211 device->set_product_string(base::UTF8ToUTF16(value));
212 }
213 value = udev_device_get_sysattr_value(udev_device.get(), "serial");
214 if (value) {
215 device->set_serial_number(base::UTF8ToUTF16(value));
216 }
217
218 value = udev_device_get_devnode(udev_device.get());
219 if (value) {
220 device->set_device_path(value);
221 task_runner->PostTask(FROM_HERE, success_closure);
reillyg5fcec062015-06-17 00:44:24222 return;
reillyg91fa9952015-06-15 21:47:19223 }
reillyg5fcec062015-06-17 00:44:24224
reillyg91fa9952015-06-15 21:47:19225 break;
226 }
227 }
228
229 task_runner->PostTask(FROM_HERE, failure_closure);
230}
231
232#else
233
234void OnReadStringDescriptor(
235 const base::Callback<void(const base::string16&)>& callback,
236 UsbTransferStatus status,
237 scoped_refptr<net::IOBuffer> buffer,
238 size_t length) {
239 if (status != USB_TRANSFER_COMPLETED || length < 2) {
240 callback.Run(base::string16());
241 } else {
242 // Take the lesser of the length of data returned by the device and the
243 // length reported in the descriptor.
244 size_t internal_length = reinterpret_cast<uint8*>(buffer->data())[0];
245 length = std::min(length, internal_length);
246 // Cut off the first 2 bytes of the descriptor which are the length and
247 // descriptor type (always STRING).
248 callback.Run(base::string16(
249 reinterpret_cast<base::char16*>(buffer->data() + 2), length / 2 - 1));
250 }
251}
252
253void ReadStringDescriptor(
254 scoped_refptr<UsbDeviceHandle> device_handle,
255 uint8 index,
256 uint16 language_id,
257 const base::Callback<void(const base::string16&)>& callback) {
258 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(256);
259 device_handle->ControlTransfer(
260 USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
261 6 /* GET_DESCRIPTOR */, 3 /* STRING */ << 8 | index, language_id, buffer,
262 256, 60, base::Bind(&OnReadStringDescriptor, callback));
263}
264
265void CloseHandleAndRunContinuation(scoped_refptr<UsbDeviceHandle> device_handle,
266 const base::Closure& continuation) {
267 device_handle->Close();
268 continuation.Run();
269}
270
271void SaveStringAndRunContinuation(
272 const base::Callback<void(const base::string16&)>& save_callback,
273 const base::Closure& continuation,
274 const base::string16& value) {
275 if (!value.empty()) {
276 save_callback.Run(value);
277 }
278 continuation.Run();
279}
280
281void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
282 uint8 manufacturer,
283 uint8 product,
284 uint8 serial_number,
285 const base::Closure& success_closure,
286 const base::string16& languages) {
287 // Default to English unless the device provides a language and then just pick
288 // the first one.
289 uint16 language_id = 0x0409;
290 if (!languages.empty()) {
291 language_id = languages[0];
292 }
293
294 scoped_refptr<UsbDeviceImpl> device =
295 static_cast<UsbDeviceImpl*>(device_handle->GetDevice().get());
296 base::Closure continuation =
297 base::BarrierClosure(3, base::Bind(&CloseHandleAndRunContinuation,
298 device_handle, success_closure));
299
300 if (manufacturer == 0) {
301 continuation.Run();
302 } else {
303 ReadStringDescriptor(
304 device_handle, manufacturer, language_id,
305 base::Bind(&SaveStringAndRunContinuation,
306 base::Bind(&UsbDeviceImpl::set_manufacturer_string, device),
307 continuation));
308 }
309
310 if (product == 0) {
311 continuation.Run();
312 } else {
313 ReadStringDescriptor(
314 device_handle, product, language_id,
315 base::Bind(&SaveStringAndRunContinuation,
316 base::Bind(&UsbDeviceImpl::set_product_string, device),
317 continuation));
318 }
319
320 if (serial_number == 0) {
321 continuation.Run();
322 } else {
323 ReadStringDescriptor(
324 device_handle, serial_number, language_id,
325 base::Bind(&SaveStringAndRunContinuation,
326 base::Bind(&UsbDeviceImpl::set_serial_number, device),
327 continuation));
328 }
329}
330
331void ReadDeviceLanguage(uint8 manufacturer,
332 uint8 product,
333 uint8 serial_number,
334 const base::Closure& success_closure,
335 const base::Closure& failure_closure,
336 scoped_refptr<UsbDeviceHandle> device_handle) {
337 if (device_handle) {
338 ReadStringDescriptor(
339 device_handle, 0, 0,
340 base::Bind(&OnReadLanguageIds, device_handle, manufacturer, product,
341 serial_number, success_closure));
342 } else {
343 failure_closure.Run();
344 }
345}
346
347#endif // USE_UDEV
348
reillygb87cb272015-04-16 19:11:04349} // namespace
350
reillyg45919812015-01-22 02:39:59351// static
352UsbService* UsbServiceImpl::Create(
reillygb87cb272015-04-16 19:11:04353 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
reillyg45919812015-01-22 02:39:59354 PlatformUsbContext context = NULL;
355 const int rv = libusb_init(&context);
356 if (rv != LIBUSB_SUCCESS) {
reillyg0f2dc632015-02-23 20:02:08357 USB_LOG(ERROR) << "Failed to initialize libusb: "
358 << ConvertPlatformUsbErrorToString(rv);
reillyg45919812015-01-22 02:39:59359 return nullptr;
360 }
361 if (!context) {
362 return nullptr;
363 }
364
reillygb87cb272015-04-16 19:11:04365 return new UsbServiceImpl(context, blocking_task_runner);
[email protected]62269732013-07-02 19:51:31366}
367
reillyge471fab2014-08-29 01:58:43368UsbServiceImpl::UsbServiceImpl(
369 PlatformUsbContext context,
reillygb87cb272015-04-16 19:11:04370 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
reillyge471fab2014-08-29 01:58:43371 : context_(new UsbContext(context)),
reillygb87cb272015-04-16 19:11:04372 task_runner_(base::ThreadTaskRunnerHandle::Get()),
373 blocking_task_runner_(blocking_task_runner),
374#if defined(OS_WIN)
375 device_observer_(this),
376#endif
reillyg257f43092015-01-08 00:48:10377 weak_factory_(this) {
reillygb87cb272015-04-16 19:11:04378 base::MessageLoop::current()->AddDestructionObserver(this);
379
reillyg0ae3a9992015-01-05 20:12:42380 int rv = libusb_hotplug_register_callback(
381 context_->context(),
382 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
383 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
reillyg91fa9952015-06-15 21:47:19384 static_cast<libusb_hotplug_flag>(0), LIBUSB_HOTPLUG_MATCH_ANY,
reillyg0ae3a9992015-01-05 20:12:42385 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
386 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
387 if (rv == LIBUSB_SUCCESS) {
388 hotplug_enabled_ = true;
389 }
reillyg91fa9952015-06-15 21:47:19390
reillygef1a7a52015-06-17 16:50:15391 RefreshDevices();
reillyg91fa9952015-06-15 21:47:19392#if defined(OS_WIN)
393 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
394 if (device_monitor) {
395 device_observer_.Add(device_monitor);
396 }
397#endif // OS_WIN
[email protected]e1954872014-04-13 17:43:29398}
399
[email protected]ad2263f2014-05-05 13:57:50400UsbServiceImpl::~UsbServiceImpl() {
reillygb87cb272015-04-16 19:11:04401 base::MessageLoop::current()->RemoveDestructionObserver(this);
402
reillyg0ae3a9992015-01-05 20:12:42403 if (hotplug_enabled_) {
404 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
405 }
406 for (const auto& map_entry : devices_) {
407 map_entry.second->OnDisconnect();
[email protected]22ac24e2012-10-03 17:56:05408 }
[email protected]22ac24e2012-10-03 17:56:05409}
410
rockotdfbc94d1d2015-06-01 20:53:09411scoped_refptr<UsbDevice> UsbServiceImpl::GetDevice(const std::string& guid) {
reillygb87cb272015-04-16 19:11:04412 DCHECK(CalledOnValidThread());
rockotdfbc94d1d2015-06-01 20:53:09413 DeviceMap::iterator it = devices_.find(guid);
reillygb87cb272015-04-16 19:11:04414 if (it != devices_.end()) {
415 return it->second;
416 }
417 return NULL;
418}
419
420void UsbServiceImpl::GetDevices(const GetDevicesCallback& callback) {
[email protected]e1954872014-04-13 17:43:29421 DCHECK(CalledOnValidThread());
[email protected]d165a6442013-08-08 19:38:11422
reillygef1a7a52015-06-17 16:50:15423 if (hotplug_enabled_ && !enumeration_in_progress_) {
reillygb87cb272015-04-16 19:11:04424 // The device list is updated live when hotplug events are supported.
425 std::vector<scoped_refptr<UsbDevice>> devices;
426 for (const auto& map_entry : devices_) {
427 devices.push_back(map_entry.second);
[email protected]d165a6442013-08-08 19:38:11428 }
reillygb87cb272015-04-16 19:11:04429 callback.Run(devices);
430 } else {
reillyg91fa9952015-06-15 21:47:19431 pending_enumeration_callbacks_.push_back(callback);
reillygef1a7a52015-06-17 16:50:15432 RefreshDevices();
[email protected]22ac24e2012-10-03 17:56:05433 }
[email protected]22ac24e2012-10-03 17:56:05434}
[email protected]b5508682014-04-22 17:10:01435
reillyg8cbc3ce2015-04-03 07:39:43436#if defined(OS_WIN)
reillyg8cbc3ce2015-04-03 07:39:43437
reillygb87cb272015-04-16 19:11:04438void UsbServiceImpl::OnDeviceAdded(const GUID& class_guid,
439 const std::string& device_path) {
440 // Only the root node of a composite USB device has the class GUID
441 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
442 // This first pass filter will catch anything that's sitting on the USB bus
443 // (including devices on 3rd party USB controllers) to avoid the more
444 // expensive driver check that needs to be done on the FILE thread.
445 if (device_path.find("usb") != std::string::npos) {
reillygef1a7a52015-06-17 16:50:15446 pending_path_enumerations_.push(device_path);
447 RefreshDevices();
reillyg8cbc3ce2015-04-03 07:39:43448 }
449}
reillygb87cb272015-04-16 19:11:04450
451void UsbServiceImpl::OnDeviceRemoved(const GUID& class_guid,
452 const std::string& device_path) {
reillygef1a7a52015-06-17 16:50:15453 // The root USB device node is removed last.
reillygb87cb272015-04-16 19:11:04454 if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) {
reillygef1a7a52015-06-17 16:50:15455 RefreshDevices();
reillygb87cb272015-04-16 19:11:04456 }
457}
458
reillyg8cbc3ce2015-04-03 07:39:43459#endif // OS_WIN
460
reillygb87cb272015-04-16 19:11:04461void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
462 DCHECK(CalledOnValidThread());
463 delete this;
464}
465
reillygef1a7a52015-06-17 16:50:15466void UsbServiceImpl::RefreshDevices() {
reillygb87cb272015-04-16 19:11:04467 DCHECK(CalledOnValidThread());
reillygef1a7a52015-06-17 16:50:15468
469 if (enumeration_in_progress_) {
470 return;
471 }
472
473 enumeration_in_progress_ = true;
reillyg91fa9952015-06-15 21:47:19474 DCHECK(devices_being_enumerated_.empty());
reillygb87cb272015-04-16 19:11:04475
reillygef1a7a52015-06-17 16:50:15476 std::string device_path;
477 if (!pending_path_enumerations_.empty()) {
478 device_path = pending_path_enumerations_.front();
479 pending_path_enumerations_.pop();
reillygb87cb272015-04-16 19:11:04480 }
reillygef1a7a52015-06-17 16:50:15481
482 blocking_task_runner_->PostTask(
483 FROM_HERE,
484 base::Bind(&GetDeviceListOnBlockingThread, device_path, context_,
485 task_runner_, base::Bind(&UsbServiceImpl::OnDeviceList,
486 weak_factory_.GetWeakPtr())));
reillygb87cb272015-04-16 19:11:04487}
488
reillyg91fa9952015-06-15 21:47:19489void UsbServiceImpl::OnDeviceList(libusb_device** platform_devices,
490 size_t device_count) {
491 DCHECK(CalledOnValidThread());
492 if (!platform_devices) {
493 RefreshDevicesComplete();
reillygb87cb272015-04-16 19:11:04494 return;
495 }
496
reillyg91fa9952015-06-15 21:47:19497 base::Closure refresh_complete =
498 base::BarrierClosure(static_cast<int>(device_count),
499 base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
500 weak_factory_.GetWeakPtr()));
501 std::list<PlatformUsbDevice> new_devices;
502
503 // Look for new and existing devices.
504 for (size_t i = 0; i < device_count; ++i) {
reillygb87cb272015-04-16 19:11:04505 PlatformUsbDevice platform_device = platform_devices[i];
reillyg91fa9952015-06-15 21:47:19506 auto it = platform_devices_.find(platform_device);
507
508 if (it == platform_devices_.end()) {
reillygb87cb272015-04-16 19:11:04509 libusb_ref_device(platform_device);
reillyg91fa9952015-06-15 21:47:19510 new_devices.push_back(platform_device);
511 } else {
512 it->second->set_visited(true);
513 refresh_complete.Run();
reillygb87cb272015-04-16 19:11:04514 }
515 }
516
reillyg91fa9952015-06-15 21:47:19517 // Remove devices not seen in this enumeration.
518 for (PlatformDeviceMap::iterator it = platform_devices_.begin();
519 it != platform_devices_.end();
520 /* incremented internally */) {
521 PlatformDeviceMap::iterator current = it++;
522 const scoped_refptr<UsbDeviceImpl>& device = current->second;
523 if (device->was_visited()) {
524 device->set_visited(false);
525 } else {
526 RemoveDevice(device);
527 }
528 }
529
530 for (PlatformUsbDevice platform_device : new_devices) {
531 EnumerateDevice(platform_device, refresh_complete);
532 }
533
534 libusb_free_device_list(platform_devices, true);
reillygb87cb272015-04-16 19:11:04535}
536
reillyg91fa9952015-06-15 21:47:19537void UsbServiceImpl::RefreshDevicesComplete() {
reillygef1a7a52015-06-17 16:50:15538 DCHECK(CalledOnValidThread());
539 DCHECK(enumeration_in_progress_);
540
reillygb87cb272015-04-16 19:11:04541 enumeration_ready_ = true;
reillygef1a7a52015-06-17 16:50:15542 enumeration_in_progress_ = false;
543 devices_being_enumerated_.clear();
reillygb87cb272015-04-16 19:11:04544
reillyg91fa9952015-06-15 21:47:19545 if (!pending_enumeration_callbacks_.empty()) {
reillygb87cb272015-04-16 19:11:04546 std::vector<scoped_refptr<UsbDevice>> devices;
547 for (const auto& map_entry : devices_) {
548 devices.push_back(map_entry.second);
549 }
550
reillyg91fa9952015-06-15 21:47:19551 std::vector<GetDevicesCallback> callbacks;
552 callbacks.swap(pending_enumeration_callbacks_);
553 for (const GetDevicesCallback& callback : callbacks) {
reillygb87cb272015-04-16 19:11:04554 callback.Run(devices);
555 }
556 }
reillyg91fa9952015-06-15 21:47:19557
558 if (!pending_path_enumerations_.empty()) {
reillygef1a7a52015-06-17 16:50:15559 RefreshDevices();
reillyg91fa9952015-06-15 21:47:19560 }
reillygb87cb272015-04-16 19:11:04561}
562
reillyg91fa9952015-06-15 21:47:19563void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device,
564 const base::Closure& refresh_complete) {
565 devices_being_enumerated_.insert(platform_device);
reillygb87cb272015-04-16 19:11:04566
reillyg91fa9952015-06-15 21:47:19567 libusb_device_descriptor descriptor;
568 int rv = libusb_get_device_descriptor(platform_device, &descriptor);
569 if (rv == LIBUSB_SUCCESS) {
570 scoped_refptr<UsbDeviceImpl> device(
571 new UsbDeviceImpl(context_, platform_device, descriptor.idVendor,
572 descriptor.idProduct, blocking_task_runner_));
573
574 base::Closure add_device =
575 base::Bind(&UsbServiceImpl::AddDevice, weak_factory_.GetWeakPtr(),
576 refresh_complete, device);
577
578#if defined(USE_UDEV)
579 blocking_task_runner_->PostTask(
580 FROM_HERE, base::Bind(&EnumerateUdevDevice, device, task_runner_,
581 add_device, refresh_complete));
582#else
583 if (descriptor.iManufacturer == 0 && descriptor.iProduct == 0 &&
584 descriptor.iSerialNumber == 0) {
585 // Don't bother disturbing the device if it has no string descriptors to
586 // offer.
587 add_device.Run();
588 } else {
589 device->Open(base::Bind(&ReadDeviceLanguage, descriptor.iManufacturer,
590 descriptor.iProduct, descriptor.iSerialNumber,
591 add_device, refresh_complete));
592 }
593#endif
594 } else {
595 USB_LOG(EVENT) << "Failed to get device descriptor: "
596 << ConvertPlatformUsbErrorToString(rv);
597 refresh_complete.Run();
598 }
599}
600
601void UsbServiceImpl::AddDevice(const base::Closure& refresh_complete,
602 scoped_refptr<UsbDeviceImpl> device) {
603 auto it = devices_being_enumerated_.find(device->platform_device());
604 if (it == devices_being_enumerated_.end()) {
605 // Device was removed while being enumerated.
606 refresh_complete.Run();
607 return;
608 }
reillyg91fa9952015-06-15 21:47:19609
610 platform_devices_[device->platform_device()] = device;
rockotdfbc94d1d2015-06-01 20:53:09611 DCHECK(!ContainsKey(devices_, device->guid()));
612 devices_[device->guid()] = device;
reillygb87cb272015-04-16 19:11:04613
614 USB_LOG(USER) << "USB device added: vendor=" << device->vendor_id() << " \""
615 << device->manufacturer_string()
616 << "\", product=" << device->product_id() << " \""
617 << device->product_string() << "\", serial=\""
rockotdfbc94d1d2015-06-01 20:53:09618 << device->serial_number() << "\", guid=" << device->guid();
reillygb87cb272015-04-16 19:11:04619
620 if (enumeration_ready_) {
621 NotifyDeviceAdded(device);
622 }
623
reillyg91fa9952015-06-15 21:47:19624 refresh_complete.Run();
reillygb87cb272015-04-16 19:11:04625}
626
627void UsbServiceImpl::RemoveDevice(scoped_refptr<UsbDeviceImpl> device) {
628 platform_devices_.erase(device->platform_device());
rockotdfbc94d1d2015-06-01 20:53:09629 devices_.erase(device->guid());
reillygb87cb272015-04-16 19:11:04630
rockotdfbc94d1d2015-06-01 20:53:09631 USB_LOG(USER) << "USB device removed: guid=" << device->guid();
reillygb87cb272015-04-16 19:11:04632
633 NotifyDeviceRemoved(device);
634 device->OnDisconnect();
635}
636
reillyg0ae3a9992015-01-05 20:12:42637// static
638int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
639 PlatformUsbDevice device,
640 libusb_hotplug_event event,
641 void* user_data) {
642 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
643 // around registering, deregistering and calling hotplug callback functions
644 // and so guarantees that this function will not be called by the event
645 // processing thread after it has been deregistered.
646 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data);
647 switch (event) {
648 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
reillygb87cb272015-04-16 19:11:04649 libusb_ref_device(device); // Released in OnPlatformDeviceAdded.
reillyg0ae3a9992015-01-05 20:12:42650 if (self->task_runner_->BelongsToCurrentThread()) {
reillygb87cb272015-04-16 19:11:04651 self->OnPlatformDeviceAdded(device);
reillyg0ae3a9992015-01-05 20:12:42652 } else {
653 self->task_runner_->PostTask(
reillygb87cb272015-04-16 19:11:04654 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded,
reillyg0ae3a9992015-01-05 20:12:42655 base::Unretained(self), device));
656 }
657 break;
658 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
reillygb87cb272015-04-16 19:11:04659 libusb_ref_device(device); // Released in OnPlatformDeviceRemoved.
reillyg0ae3a9992015-01-05 20:12:42660 if (self->task_runner_->BelongsToCurrentThread()) {
reillygb87cb272015-04-16 19:11:04661 self->OnPlatformDeviceRemoved(device);
reillyg0ae3a9992015-01-05 20:12:42662 } else {
663 self->task_runner_->PostTask(
reillygb87cb272015-04-16 19:11:04664 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved,
reillyg0ae3a9992015-01-05 20:12:42665 base::Unretained(self), device));
666 }
667 break;
668 default:
669 NOTREACHED();
670 }
671
672 return 0;
673}
674
reillygb87cb272015-04-16 19:11:04675void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device) {
reillyg0ae3a9992015-01-05 20:12:42676 DCHECK(CalledOnValidThread());
677 DCHECK(!ContainsKey(platform_devices_, platform_device));
reillyg91fa9952015-06-15 21:47:19678 EnumerateDevice(platform_device, base::Bind(&base::DoNothing));
679 libusb_unref_device(platform_device);
reillyg0ae3a9992015-01-05 20:12:42680}
681
reillygb87cb272015-04-16 19:11:04682void UsbServiceImpl::OnPlatformDeviceRemoved(
683 PlatformUsbDevice platform_device) {
reillyg0ae3a9992015-01-05 20:12:42684 DCHECK(CalledOnValidThread());
reillyg0ae3a9992015-01-05 20:12:42685 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device);
686 if (it != platform_devices_.end()) {
reillyg91fa9952015-06-15 21:47:19687 RemoveDevice(it->second);
reillyg0ae3a9992015-01-05 20:12:42688 } else {
reillyg91fa9952015-06-15 21:47:19689 DCHECK(ContainsKey(devices_being_enumerated_, platform_device));
690 devices_being_enumerated_.erase(platform_device);
reillyg0ae3a9992015-01-05 20:12:42691 }
reillyg0ae3a9992015-01-05 20:12:42692 libusb_unref_device(platform_device);
693}
694
reillygd77718d2014-09-04 00:57:56695} // namespace device