hid_connection_linux.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_linux.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <errno.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <fcntl.h>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <libudev.h>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <linux/hidraw.h>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tuple.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service_linux.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHidrawSubsystem[] = "hidraw";
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ScopedUdevDevicePtr udev_raw_device)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : HidConnection(device_info),
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      initialized_(false) {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  udev_device* dev = udev_raw_device.get();
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string dev_node;
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!FindHidrawDevNode(dev, &dev_node)) {
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Cannot open HID device as hidraw device.";
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PlatformFileError error;
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int flags = base::PLATFORM_FILE_OPEN |
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::PLATFORM_FILE_READ |
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::PLATFORM_FILE_WRITE |
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::PLATFORM_FILE_EXCLUSIVE_READ |
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::PLATFORM_FILE_EXCLUSIVE_WRITE;
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PlatformFile device_file = base::CreatePlatformFile(
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::FilePath(dev_node),
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      flags,
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &error);
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error || device_file <= 0) {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << error;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (device_file)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::ClosePlatformFile(device_file);
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (fcntl(device_file, F_SETFL, fcntl(device_file, F_GETFL) | O_NONBLOCK)) {
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "Failed to set non-blocking flag to device file.";
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_file_ = device_file;
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_file_,
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true,
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::MessageLoopForIO::WATCH_READ_WRITE,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &device_file_watcher_,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this)) {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Cannot start watching file descriptor.";
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  initialized_ = true;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::~HidConnectionLinux() {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Disconnect();
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(fd, device_file_);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(initialized_);
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uint8 buffer[1024] = {0};
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int bytes = read(device_file_, buffer, 1024);
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (bytes < 0) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (errno == EAGAIN) {
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Disconnect();
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(bytes));
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memcpy(io_buffer->data(), buffer, bytes);
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  input_reports_.push(std::make_pair(io_buffer, bytes));
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProcessReadQueue();
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {}
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Disconnect() {
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!initialized_)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  initialized_ = false;
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_file_watcher_.StopWatchingFileDescriptor();
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  close(device_file_);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (!read_queue_.empty()) {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PendingRequest callback = read_queue_.front();
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    read_queue_.pop();
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.c.Run(false, 0);
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Read(scoped_refptr<net::IOBuffer> buffer,
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              size_t size,
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const IOCallback& callback) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!initialized_) {
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(read_queue_.empty());
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // There might be unread reports.
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!input_reports_.empty()){
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      read_queue_.push(MakeTuple(buffer, size, callback));
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ProcessReadQueue();
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    read_queue_.push(MakeTuple(buffer, size, callback));
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ProcessReadQueue();
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Write(scoped_refptr<net::IOBuffer> buffer,
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               size_t size,
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               const IOCallback& callback) {
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!initialized_) {
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int bytes = write(device_file_, buffer->data(), size);
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (bytes < 0) {
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Disconnect();
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback.Run(false, 0);
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback.Run(true, bytes);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer,
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          size_t size,
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          const IOCallback& callback) {
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!initialized_) {
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTIMPLEMENTED();
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           size_t size,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           const IOCallback& callback) {
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!initialized_) {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTIMPLEMENTED();
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::ProcessReadQueue() {
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while(read_queue_.size() && input_reports_.size()) {
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PendingRequest request = read_queue_.front();
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    read_queue_.pop();
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PendingReport report = input_reports_.front();
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (report.second > request.b) {
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request.c.Run(false, report.second);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      memcpy(request.a->data(), report.first->data(), report.second);
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      input_reports_.pop();
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request.c.Run(true, report.second);
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HidConnectionLinux::FindHidrawDevNode(udev_device* parent,
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           std::string* result) {
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  udev* udev = udev_device_get_udev(parent);
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!udev)
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev));
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!enumerate)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (udev_enumerate_add_match_subsystem(enumerate.get(), kHidrawSubsystem)) {
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (udev_enumerate_scan_devices(enumerate.get())) {
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char* parent_path = udev_device_get_devpath(parent);
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (udev_list_entry* i = devices; i != NULL;
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      i = udev_list_entry_get_next(i)) {
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ScopedUdevDevicePtr hid_dev(
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        udev_device_new_from_syspath(udev, udev_list_entry_get_name(i)));
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const char* raw_path = udev_device_get_devnode(hid_dev.get());
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (strncmp(parent_path,
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                udev_device_get_devpath(hid_dev.get()),
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                strlen(parent_path)) == 0 &&
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        raw_path) {
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *result = raw_path;
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
232