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