Suppress -Woverloaded-virtual for mesa's glsl library.
[chromium-blink-merge.git] / device / usb / usb_service_impl.cc
blob5c326585169fd3cd25c64ba8a29d585a7c92ddaa
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_service_impl.h"
7 #include <list>
8 #include <set>
10 #include "base/barrier_closure.h"
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "components/device_event_log/device_event_log.h"
20 #include "device/usb/usb_device_handle.h"
21 #include "device/usb/usb_error.h"
22 #include "device/usb/webusb_descriptors.h"
23 #include "third_party/libusb/src/libusb/libusb.h"
25 #if defined(OS_WIN)
26 #include <setupapi.h>
27 #include <usbiodef.h>
29 #include "base/strings/string_util.h"
30 #endif // OS_WIN
32 #if defined(USE_UDEV)
33 #include "device/udev_linux/scoped_udev.h"
34 #endif // USE_UDEV
36 using net::IOBufferWithSize;
38 namespace device {
40 namespace {
42 // Standard USB requests and descriptor types:
43 const uint16_t kUsbVersion2_1 = 0x0210;
44 const uint8_t kGetDescriptorRequest = 0x06;
45 const uint8_t kStringDescriptorType = 0x03;
46 const uint8_t kBosDescriptorType = 0x0F;
48 // WebUSB requests:
49 const uint8_t kGetAllowedOriginsRequest = 0x01;
50 const uint8_t kGetLandingPageRequest = 0x02;
52 const int kControlTransferTimeout = 60000; // 1 minute
54 #if defined(OS_WIN)
56 // Wrapper around a HDEVINFO that automatically destroys it.
57 class ScopedDeviceInfoList {
58 public:
59 explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {}
61 ~ScopedDeviceInfoList() {
62 if (valid()) {
63 SetupDiDestroyDeviceInfoList(handle_);
67 bool valid() { return handle_ != INVALID_HANDLE_VALUE; }
69 HDEVINFO get() { return handle_; }
71 private:
72 HDEVINFO handle_;
74 DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList);
77 // Wrapper around an SP_DEVINFO_DATA that initializes it properly and
78 // automatically deletes it.
79 class ScopedDeviceInfo {
80 public:
81 ScopedDeviceInfo() {
82 memset(&dev_info_data_, 0, sizeof(dev_info_data_));
83 dev_info_data_.cbSize = sizeof(dev_info_data_);
86 ~ScopedDeviceInfo() {
87 if (dev_info_set_ != INVALID_HANDLE_VALUE) {
88 SetupDiDeleteDeviceInfo(dev_info_set_, &dev_info_data_);
92 // Once the SP_DEVINFO_DATA has been populated it must be freed using the
93 // HDEVINFO it was created from.
94 void set_valid(HDEVINFO dev_info_set) {
95 DCHECK(dev_info_set_ == INVALID_HANDLE_VALUE);
96 DCHECK(dev_info_set != INVALID_HANDLE_VALUE);
97 dev_info_set_ = dev_info_set;
100 PSP_DEVINFO_DATA get() { return &dev_info_data_; }
102 private:
103 HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE;
104 SP_DEVINFO_DATA dev_info_data_;
107 bool IsWinUsbInterface(const std::string& device_path) {
108 ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL));
109 if (!dev_info_list.valid()) {
110 USB_PLOG(ERROR) << "Failed to create a device information set";
111 return false;
114 // This will add the device to |dev_info_list| so we can query driver info.
115 if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0,
116 NULL)) {
117 USB_PLOG(ERROR) << "Failed to get device interface data for "
118 << device_path;
119 return false;
122 ScopedDeviceInfo dev_info;
123 if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) {
124 USB_PLOG(ERROR) << "Failed to get device info for " << device_path;
125 return false;
127 dev_info.set_valid(dev_info_list.get());
129 DWORD reg_data_type;
130 BYTE buffer[256];
131 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(),
132 SPDRP_SERVICE, &reg_data_type,
133 &buffer[0], sizeof buffer, NULL)) {
134 USB_PLOG(ERROR) << "Failed to get device service property";
135 return false;
137 if (reg_data_type != REG_SZ) {
138 USB_LOG(ERROR) << "Unexpected data type for driver service: "
139 << reg_data_type;
140 return false;
143 USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << ".";
144 if (base::StartsWith(reinterpret_cast<const char*>(buffer), "WinUSB",
145 base::CompareCase::INSENSITIVE_ASCII))
146 return true;
147 return false;
150 #endif // OS_WIN
152 void GetDeviceListOnBlockingThread(
153 const std::string& new_device_path,
154 scoped_refptr<UsbContext> usb_context,
155 scoped_refptr<base::SequencedTaskRunner> task_runner,
156 base::Callback<void(libusb_device**, size_t)> callback) {
157 #if defined(OS_WIN)
158 if (!new_device_path.empty()) {
159 if (!IsWinUsbInterface(new_device_path)) {
160 // Wait to call libusb_get_device_list until libusb will be able to find
161 // a WinUSB interface for the device.
162 task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
163 return;
166 #endif // defined(OS_WIN)
168 libusb_device** platform_devices = NULL;
169 const ssize_t device_count =
170 libusb_get_device_list(usb_context->context(), &platform_devices);
171 if (device_count < 0) {
172 USB_LOG(ERROR) << "Failed to get device list: "
173 << ConvertPlatformUsbErrorToString(device_count);
174 task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
175 return;
178 task_runner->PostTask(FROM_HERE,
179 base::Bind(callback, platform_devices, device_count));
182 void OnReadStringDescriptor(
183 const base::Callback<void(const base::string16&)>& callback,
184 UsbTransferStatus status,
185 scoped_refptr<net::IOBuffer> buffer,
186 size_t length) {
187 base::string16 string;
188 if (status == USB_TRANSFER_COMPLETED &&
189 ParseUsbStringDescriptor(
190 std::vector<uint8>(buffer->data(), buffer->data() + length),
191 &string)) {
192 callback.Run(string);
193 } else {
194 callback.Run(base::string16());
198 void ReadStringDescriptor(
199 scoped_refptr<UsbDeviceHandle> device_handle,
200 uint8 index,
201 uint16 language_id,
202 const base::Callback<void(const base::string16&)>& callback) {
203 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(256);
204 device_handle->ControlTransfer(
205 USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
206 kGetDescriptorRequest, kStringDescriptorType << 8 | index, language_id,
207 buffer, buffer->size(), kControlTransferTimeout,
208 base::Bind(&OnReadStringDescriptor, callback));
211 void OnReadWebUsbLandingPage(scoped_refptr<UsbDevice> device,
212 const base::Closure& callback,
213 UsbTransferStatus status,
214 scoped_refptr<net::IOBuffer> buffer,
215 size_t length) {
216 if (status != USB_TRANSFER_COMPLETED) {
217 USB_LOG(EVENT) << "Failed to read WebUSB landing page.";
218 callback.Run();
219 return;
222 GURL landing_page;
223 if (ParseWebUsbUrlDescriptor(
224 std::vector<uint8_t>(buffer->data(), buffer->data() + length),
225 &landing_page)) {
226 UsbDeviceImpl* device_impl = static_cast<UsbDeviceImpl*>(device.get());
227 device_impl->set_webusb_landing_page(landing_page);
229 callback.Run();
232 void ReadWebUsbLandingPage(scoped_refptr<UsbDeviceHandle> device_handle,
233 const base::Closure& callback,
234 uint8 vendor_code) {
235 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(256);
236 device_handle->ControlTransfer(
237 USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
238 vendor_code, 0, kGetLandingPageRequest, buffer, buffer->size(),
239 kControlTransferTimeout,
240 base::Bind(&OnReadWebUsbLandingPage, device_handle->GetDevice(),
241 callback));
244 void OnReadWebUsbAllowedOrigins(scoped_refptr<UsbDevice> device,
245 const base::Closure& callback,
246 UsbTransferStatus status,
247 scoped_refptr<net::IOBuffer> buffer,
248 size_t length) {
249 if (status != USB_TRANSFER_COMPLETED) {
250 USB_LOG(EVENT) << "Failed to read WebUSB allowed origins.";
251 callback.Run();
252 return;
255 scoped_ptr<WebUsbDescriptorSet> descriptors(new WebUsbDescriptorSet());
256 if (descriptors->Parse(
257 std::vector<uint8>(buffer->data(), buffer->data() + length))) {
258 UsbDeviceImpl* device_impl = static_cast<UsbDeviceImpl*>(device.get());
259 device_impl->set_webusb_allowed_origins(descriptors.Pass());
261 callback.Run();
264 void OnReadWebUsbAllowedOriginsHeader(
265 scoped_refptr<UsbDeviceHandle> device_handle,
266 const base::Closure& callback,
267 uint8 vendor_code,
268 UsbTransferStatus status,
269 scoped_refptr<net::IOBuffer> buffer,
270 size_t length) {
271 if (status != USB_TRANSFER_COMPLETED || length != 4) {
272 USB_LOG(EVENT) << "Failed to read WebUSB allowed origins header.";
273 callback.Run();
274 return;
277 uint16 new_length = buffer->data()[2] | (buffer->data()[3] << 8);
278 scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
279 device_handle->ControlTransfer(
280 USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
281 vendor_code, 0, kGetAllowedOriginsRequest, new_buffer, new_buffer->size(),
282 kControlTransferTimeout,
283 base::Bind(&OnReadWebUsbAllowedOrigins, device_handle->GetDevice(),
284 callback));
287 void ReadWebUsbAllowedOrigins(scoped_refptr<UsbDeviceHandle> device_handle,
288 const base::Closure& callback,
289 uint8 vendor_code) {
290 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(4);
291 device_handle->ControlTransfer(
292 USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
293 vendor_code, 0, kGetAllowedOriginsRequest, buffer, buffer->size(),
294 kControlTransferTimeout,
295 base::Bind(&OnReadWebUsbAllowedOriginsHeader, device_handle, callback,
296 vendor_code));
299 void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
300 const base::Closure& callback,
301 UsbTransferStatus status,
302 scoped_refptr<net::IOBuffer> buffer,
303 size_t length) {
304 if (status != USB_TRANSFER_COMPLETED) {
305 USB_LOG(EVENT) << "Failed to read BOS descriptor.";
306 callback.Run();
307 return;
310 WebUsbPlatformCapabilityDescriptor descriptor;
311 if (!descriptor.ParseFromBosDescriptor(
312 std::vector<uint8>(buffer->data(), buffer->data() + length))) {
313 callback.Run();
314 return;
317 base::Closure barrier = base::BarrierClosure(2, callback);
318 ReadWebUsbLandingPage(device_handle, barrier, descriptor.vendor_code);
319 ReadWebUsbAllowedOrigins(device_handle, barrier, descriptor.vendor_code);
322 void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
323 const base::Closure& callback,
324 UsbTransferStatus status,
325 scoped_refptr<net::IOBuffer> buffer,
326 size_t length) {
327 if (status != USB_TRANSFER_COMPLETED || length != 5) {
328 USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
329 callback.Run();
330 return;
333 uint16 new_length = buffer->data()[2] | (buffer->data()[3] << 8);
334 scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
335 device_handle->ControlTransfer(
336 USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
337 kGetDescriptorRequest, kBosDescriptorType << 8, 0, new_buffer,
338 new_buffer->size(), kControlTransferTimeout,
339 base::Bind(&OnReadBosDescriptor, device_handle, callback));
342 void ReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
343 const base::Closure& callback) {
344 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(5);
345 device_handle->ControlTransfer(
346 USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
347 kGetDescriptorRequest, kBosDescriptorType << 8, 0, buffer, buffer->size(),
348 kControlTransferTimeout,
349 base::Bind(&OnReadBosDescriptorHeader, device_handle, callback));
352 void CloseHandleAndRunContinuation(scoped_refptr<UsbDeviceHandle> device_handle,
353 const base::Closure& continuation) {
354 device_handle->Close();
355 continuation.Run();
358 void SaveStringAndRunContinuation(
359 const base::Callback<void(const base::string16&)>& save_callback,
360 const base::Closure& continuation,
361 const base::string16& value) {
362 if (!value.empty()) {
363 save_callback.Run(value);
365 continuation.Run();
368 // This function runs |barrier| once for every string it tries to read.
369 void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
370 uint8 manufacturer,
371 uint8 product,
372 uint8 serial_number,
373 const base::Closure& barrier,
374 const base::string16& languages) {
375 // Default to English unless the device provides a language and then just pick
376 // the first one.
377 uint16 language_id = 0x0409;
378 if (!languages.empty()) {
379 language_id = languages[0];
382 scoped_refptr<UsbDeviceImpl> device =
383 static_cast<UsbDeviceImpl*>(device_handle->GetDevice().get());
385 if (manufacturer != 0) {
386 ReadStringDescriptor(
387 device_handle, manufacturer, language_id,
388 base::Bind(&SaveStringAndRunContinuation,
389 base::Bind(&UsbDeviceImpl::set_manufacturer_string, device),
390 barrier));
393 if (product != 0) {
394 ReadStringDescriptor(
395 device_handle, product, language_id,
396 base::Bind(&SaveStringAndRunContinuation,
397 base::Bind(&UsbDeviceImpl::set_product_string, device),
398 barrier));
401 if (serial_number != 0) {
402 ReadStringDescriptor(
403 device_handle, serial_number, language_id,
404 base::Bind(&SaveStringAndRunContinuation,
405 base::Bind(&UsbDeviceImpl::set_serial_number, device),
406 barrier));
410 void OnDeviceOpenedReadDescriptors(
411 uint8 manufacturer,
412 uint8 product,
413 uint8 serial_number,
414 bool read_bos_descriptors,
415 const base::Closure& success_closure,
416 const base::Closure& failure_closure,
417 scoped_refptr<UsbDeviceHandle> device_handle) {
418 if (device_handle) {
419 int count = 0;
420 if (manufacturer != 0)
421 count++;
422 if (product != 0)
423 count++;
424 if (serial_number != 0)
425 count++;
426 if (read_bos_descriptors)
427 count++;
428 DCHECK_GT(count, 0);
430 base::Closure barrier =
431 base::BarrierClosure(count, base::Bind(&CloseHandleAndRunContinuation,
432 device_handle, success_closure));
434 if (manufacturer != 0 || product != 0 || serial_number != 0) {
435 ReadStringDescriptor(
436 device_handle, 0, 0,
437 base::Bind(&OnReadLanguageIds, device_handle, manufacturer, product,
438 serial_number, barrier));
441 if (read_bos_descriptors) {
442 ReadBosDescriptor(device_handle, barrier);
444 } else {
445 failure_closure.Run();
449 #if defined(USE_UDEV)
451 void EnumerateUdevDevice(scoped_refptr<UsbDeviceImpl> device,
452 bool read_bos_descriptors,
453 scoped_refptr<base::SequencedTaskRunner> task_runner,
454 const base::Closure& success_closure,
455 const base::Closure& failure_closure) {
456 ScopedUdevPtr udev(udev_new());
457 ScopedUdevEnumeratePtr udev_enumerate(udev_enumerate_new(udev.get()));
459 udev_enumerate_add_match_subsystem(udev_enumerate.get(), "usb");
460 if (udev_enumerate_scan_devices(udev_enumerate.get()) != 0) {
461 task_runner->PostTask(FROM_HERE, failure_closure);
462 return;
465 std::string bus_number =
466 base::IntToString(libusb_get_bus_number(device->platform_device()));
467 std::string device_address =
468 base::IntToString(libusb_get_device_address(device->platform_device()));
469 udev_list_entry* devices =
470 udev_enumerate_get_list_entry(udev_enumerate.get());
471 for (udev_list_entry* i = devices; i != NULL;
472 i = udev_list_entry_get_next(i)) {
473 ScopedUdevDevicePtr udev_device(
474 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
475 if (udev_device) {
476 const char* value =
477 udev_device_get_sysattr_value(udev_device.get(), "busnum");
478 if (!value || bus_number != value) {
479 continue;
481 value = udev_device_get_sysattr_value(udev_device.get(), "devnum");
482 if (!value || device_address != value) {
483 continue;
486 value = udev_device_get_sysattr_value(udev_device.get(), "manufacturer");
487 if (value) {
488 device->set_manufacturer_string(base::UTF8ToUTF16(value));
490 value = udev_device_get_sysattr_value(udev_device.get(), "product");
491 if (value) {
492 device->set_product_string(base::UTF8ToUTF16(value));
494 value = udev_device_get_sysattr_value(udev_device.get(), "serial");
495 if (value) {
496 device->set_serial_number(base::UTF8ToUTF16(value));
499 value = udev_device_get_devnode(udev_device.get());
500 if (value) {
501 device->set_device_path(value);
503 if (read_bos_descriptors) {
504 task_runner->PostTask(
505 FROM_HERE,
506 base::Bind(&UsbDevice::Open, device,
507 base::Bind(&OnDeviceOpenedReadDescriptors, 0, 0, 0,
508 true, success_closure, failure_closure)));
509 } else {
510 task_runner->PostTask(FROM_HERE, success_closure);
512 return;
515 break;
519 task_runner->PostTask(FROM_HERE, failure_closure);
522 #endif // USE_UDEV
524 } // namespace
526 UsbServiceImpl::UsbServiceImpl(
527 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
528 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
529 blocking_task_runner_(blocking_task_runner),
530 #if defined(OS_WIN)
531 device_observer_(this),
532 #endif
533 weak_factory_(this) {
534 base::MessageLoop::current()->AddDestructionObserver(this);
536 PlatformUsbContext platform_context = nullptr;
537 int rv = libusb_init(&platform_context);
538 if (rv != LIBUSB_SUCCESS || !platform_context) {
539 USB_LOG(DEBUG) << "Failed to initialize libusb: "
540 << ConvertPlatformUsbErrorToString(rv);
541 return;
543 context_ = new UsbContext(platform_context);
545 rv = libusb_hotplug_register_callback(
546 context_->context(),
547 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
548 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
549 static_cast<libusb_hotplug_flag>(0), LIBUSB_HOTPLUG_MATCH_ANY,
550 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
551 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
552 if (rv == LIBUSB_SUCCESS) {
553 hotplug_enabled_ = true;
556 RefreshDevices();
557 #if defined(OS_WIN)
558 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
559 if (device_monitor) {
560 device_observer_.Add(device_monitor);
562 #endif // OS_WIN
565 UsbServiceImpl::~UsbServiceImpl() {
566 base::MessageLoop::current()->RemoveDestructionObserver(this);
568 if (hotplug_enabled_) {
569 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
571 for (const auto& map_entry : devices_) {
572 map_entry.second->OnDisconnect();
576 scoped_refptr<UsbDevice> UsbServiceImpl::GetDevice(const std::string& guid) {
577 DCHECK(CalledOnValidThread());
578 DeviceMap::iterator it = devices_.find(guid);
579 if (it != devices_.end()) {
580 return it->second;
582 return NULL;
585 void UsbServiceImpl::GetDevices(const GetDevicesCallback& callback) {
586 DCHECK(CalledOnValidThread());
588 if (!context_) {
589 task_runner_->PostTask(
590 FROM_HERE,
591 base::Bind(callback, std::vector<scoped_refptr<UsbDevice>>()));
592 return;
595 if (hotplug_enabled_ && !enumeration_in_progress_) {
596 // The device list is updated live when hotplug events are supported.
597 std::vector<scoped_refptr<UsbDevice>> devices;
598 for (const auto& map_entry : devices_) {
599 devices.push_back(map_entry.second);
601 task_runner_->PostTask(FROM_HERE, base::Bind(callback, devices));
602 } else {
603 pending_enumeration_callbacks_.push_back(callback);
604 RefreshDevices();
608 #if defined(OS_WIN)
610 void UsbServiceImpl::OnDeviceAdded(const GUID& class_guid,
611 const std::string& device_path) {
612 // Only the root node of a composite USB device has the class GUID
613 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
614 // This first pass filter will catch anything that's sitting on the USB bus
615 // (including devices on 3rd party USB controllers) to avoid the more
616 // expensive driver check that needs to be done on the FILE thread.
617 if (device_path.find("usb") != std::string::npos) {
618 pending_path_enumerations_.push(device_path);
619 RefreshDevices();
623 void UsbServiceImpl::OnDeviceRemoved(const GUID& class_guid,
624 const std::string& device_path) {
625 // The root USB device node is removed last.
626 if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) {
627 RefreshDevices();
631 #endif // OS_WIN
633 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
634 DCHECK(CalledOnValidThread());
635 delete this;
638 void UsbServiceImpl::RefreshDevices() {
639 DCHECK(CalledOnValidThread());
640 DCHECK(context_);
642 if (enumeration_in_progress_) {
643 return;
646 enumeration_in_progress_ = true;
647 DCHECK(devices_being_enumerated_.empty());
649 std::string device_path;
650 if (!pending_path_enumerations_.empty()) {
651 device_path = pending_path_enumerations_.front();
652 pending_path_enumerations_.pop();
655 blocking_task_runner_->PostTask(
656 FROM_HERE,
657 base::Bind(&GetDeviceListOnBlockingThread, device_path, context_,
658 task_runner_, base::Bind(&UsbServiceImpl::OnDeviceList,
659 weak_factory_.GetWeakPtr())));
662 void UsbServiceImpl::OnDeviceList(libusb_device** platform_devices,
663 size_t device_count) {
664 DCHECK(CalledOnValidThread());
665 if (!platform_devices) {
666 RefreshDevicesComplete();
667 return;
670 base::Closure refresh_complete =
671 base::BarrierClosure(static_cast<int>(device_count),
672 base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
673 weak_factory_.GetWeakPtr()));
674 std::list<PlatformUsbDevice> new_devices;
676 // Look for new and existing devices.
677 for (size_t i = 0; i < device_count; ++i) {
678 PlatformUsbDevice platform_device = platform_devices[i];
679 auto it = platform_devices_.find(platform_device);
681 if (it == platform_devices_.end()) {
682 libusb_ref_device(platform_device);
683 new_devices.push_back(platform_device);
684 } else {
685 it->second->set_visited(true);
686 refresh_complete.Run();
690 // Remove devices not seen in this enumeration.
691 for (PlatformDeviceMap::iterator it = platform_devices_.begin();
692 it != platform_devices_.end();
693 /* incremented internally */) {
694 PlatformDeviceMap::iterator current = it++;
695 const scoped_refptr<UsbDeviceImpl>& device = current->second;
696 if (device->was_visited()) {
697 device->set_visited(false);
698 } else {
699 RemoveDevice(device);
703 for (PlatformUsbDevice platform_device : new_devices) {
704 EnumerateDevice(platform_device, refresh_complete);
707 libusb_free_device_list(platform_devices, true);
710 void UsbServiceImpl::RefreshDevicesComplete() {
711 DCHECK(CalledOnValidThread());
712 DCHECK(enumeration_in_progress_);
714 enumeration_ready_ = true;
715 enumeration_in_progress_ = false;
716 devices_being_enumerated_.clear();
718 if (!pending_enumeration_callbacks_.empty()) {
719 std::vector<scoped_refptr<UsbDevice>> devices;
720 for (const auto& map_entry : devices_) {
721 devices.push_back(map_entry.second);
724 std::vector<GetDevicesCallback> callbacks;
725 callbacks.swap(pending_enumeration_callbacks_);
726 for (const GetDevicesCallback& callback : callbacks) {
727 callback.Run(devices);
731 if (!pending_path_enumerations_.empty()) {
732 RefreshDevices();
736 void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device,
737 const base::Closure& refresh_complete) {
738 DCHECK(context_);
739 devices_being_enumerated_.insert(platform_device);
741 libusb_device_descriptor descriptor;
742 int rv = libusb_get_device_descriptor(platform_device, &descriptor);
743 if (rv == LIBUSB_SUCCESS) {
744 scoped_refptr<UsbDeviceImpl> device(
745 new UsbDeviceImpl(context_, platform_device, descriptor.idVendor,
746 descriptor.idProduct, blocking_task_runner_));
748 base::Closure add_device =
749 base::Bind(&UsbServiceImpl::AddDevice, weak_factory_.GetWeakPtr(),
750 refresh_complete, device);
751 bool read_bos_descriptors = descriptor.bcdUSB >= kUsbVersion2_1;
753 #if defined(USE_UDEV)
754 blocking_task_runner_->PostTask(
755 FROM_HERE,
756 base::Bind(&EnumerateUdevDevice, device, read_bos_descriptors,
757 task_runner_, add_device, refresh_complete));
758 #else
759 if (descriptor.iManufacturer == 0 && descriptor.iProduct == 0 &&
760 descriptor.iSerialNumber == 0 && !read_bos_descriptors) {
761 // Don't bother disturbing the device if it has no descriptors to offer.
762 add_device.Run();
763 } else {
764 device->Open(base::Bind(&OnDeviceOpenedReadDescriptors,
765 descriptor.iManufacturer, descriptor.iProduct,
766 descriptor.iSerialNumber, read_bos_descriptors,
767 add_device, refresh_complete));
769 #endif
770 } else {
771 USB_LOG(EVENT) << "Failed to get device descriptor: "
772 << ConvertPlatformUsbErrorToString(rv);
773 refresh_complete.Run();
777 void UsbServiceImpl::AddDevice(const base::Closure& refresh_complete,
778 scoped_refptr<UsbDeviceImpl> device) {
779 auto it = devices_being_enumerated_.find(device->platform_device());
780 if (it == devices_being_enumerated_.end()) {
781 // Device was removed while being enumerated.
782 refresh_complete.Run();
783 return;
786 platform_devices_[device->platform_device()] = device;
787 DCHECK(!ContainsKey(devices_, device->guid()));
788 devices_[device->guid()] = device;
790 USB_LOG(USER) << "USB device added: vendor=" << device->vendor_id() << " \""
791 << device->manufacturer_string()
792 << "\", product=" << device->product_id() << " \""
793 << device->product_string() << "\", serial=\""
794 << device->serial_number() << "\", guid=" << device->guid();
796 if (enumeration_ready_) {
797 NotifyDeviceAdded(device);
800 refresh_complete.Run();
803 void UsbServiceImpl::RemoveDevice(scoped_refptr<UsbDeviceImpl> device) {
804 platform_devices_.erase(device->platform_device());
805 devices_.erase(device->guid());
807 USB_LOG(USER) << "USB device removed: guid=" << device->guid();
809 NotifyDeviceRemoved(device);
810 device->OnDisconnect();
813 // static
814 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
815 PlatformUsbDevice device,
816 libusb_hotplug_event event,
817 void* user_data) {
818 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
819 // around registering, deregistering and calling hotplug callback functions
820 // and so guarantees that this function will not be called by the event
821 // processing thread after it has been deregistered.
822 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data);
823 switch (event) {
824 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
825 libusb_ref_device(device); // Released in OnPlatformDeviceAdded.
826 if (self->task_runner_->BelongsToCurrentThread()) {
827 self->OnPlatformDeviceAdded(device);
828 } else {
829 self->task_runner_->PostTask(
830 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded,
831 base::Unretained(self), device));
833 break;
834 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
835 libusb_ref_device(device); // Released in OnPlatformDeviceRemoved.
836 if (self->task_runner_->BelongsToCurrentThread()) {
837 self->OnPlatformDeviceRemoved(device);
838 } else {
839 self->task_runner_->PostTask(
840 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved,
841 base::Unretained(self), device));
843 break;
844 default:
845 NOTREACHED();
848 return 0;
851 void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device) {
852 DCHECK(CalledOnValidThread());
853 DCHECK(!ContainsKey(platform_devices_, platform_device));
854 EnumerateDevice(platform_device, base::Bind(&base::DoNothing));
855 libusb_unref_device(platform_device);
858 void UsbServiceImpl::OnPlatformDeviceRemoved(
859 PlatformUsbDevice platform_device) {
860 DCHECK(CalledOnValidThread());
861 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device);
862 if (it != platform_devices_.end()) {
863 RemoveDevice(it->second);
864 } else {
865 devices_being_enumerated_.erase(platform_device);
867 libusb_unref_device(platform_device);
870 } // namespace device