10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file. 4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_context.h" 6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/atomicops.h" 8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/logging.h" 9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/threading/platform_thread.h" 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_error.h" 12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/libusb/src/libusb/interrupt.h" 13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/libusb/src/libusb/libusb.h" 14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace device { 160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// The UsbEventHandler works around a design flaw in the libusb interface. There 18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// is currently no way to signal to libusb that any caller into one of the event 19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// handler calls should return without handling any events. 20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class UsbContext::UsbEventHandler : public base::PlatformThread::Delegate { 21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public: 22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) explicit UsbEventHandler(libusb_context* context); 23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual ~UsbEventHandler(); 24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // base::PlatformThread::Delegate 26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual void ThreadMain() OVERRIDE; 27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private: 2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::subtle::Atomic32 running_; 30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) libusb_context* context_; 31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::PlatformThreadHandle thread_handle_; 32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::WaitableEvent start_polling_; 33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UsbEventHandler); 34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}; 35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)UsbContext::UsbEventHandler::UsbEventHandler(libusb_context* context) 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : context_(context), thread_handle_(0), start_polling_(false, false) { 3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::subtle::Release_Store(&running_, 1); 39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool success = base::PlatformThread::Create(0, this, &thread_handle_); 40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(success) << "Failed to create USB IO handling thread."; 41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) start_polling_.Wait(); 42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)UsbContext::UsbEventHandler::~UsbEventHandler() { 4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::subtle::Release_Store(&running_, 0); 46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) libusb_interrupt_handle_event(context_); 47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::PlatformThread::Join(thread_handle_); 48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void UsbContext::UsbEventHandler::ThreadMain() { 51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::PlatformThread::SetName("UsbEventHandler"); 52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) VLOG(1) << "UsbEventHandler started."; 5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (base::subtle::Acquire_Load(&running_)) { 55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) start_polling_.Signal(); 56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) while (base::subtle::Acquire_Load(&running_)) { 586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const int rv = libusb_handle_events(context_); 596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (rv != LIBUSB_SUCCESS) { 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "Failed to handle events: " 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << ConvertPlatformUsbErrorToString(rv); 626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) VLOG(1) << "UsbEventHandler shutting down."; 65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)UsbContext::UsbContext(PlatformUsbContext context) : context_(context) { 68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) event_handler_ = new UsbEventHandler(context_); 70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)UsbContext::~UsbContext() { 73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // destruction of UsbEventHandler is a blocking operation. 74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delete event_handler_; 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) event_handler_ = NULL; 77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) libusb_exit(context_); 78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace device 81