hid_connection_linux.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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>
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <sys/ioctl.h>
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/file_path.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/posix/eintr_wrapper.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tuple.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service_linux.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// These are already defined in newer versions of linux/hidraw.h.
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#ifndef HIDIOCSFEATURE
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x06, len)
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#ifndef HIDIOCGFEATURE
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x07, len)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copies a buffer into a new one with a report ID byte inserted at the front.
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_refptr<net::IOBufferWithSize> CopyBufferWithReportId(
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::IOBufferWithSize> buffer,
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint8_t report_id) {
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<net::IOBufferWithSize> new_buffer(
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new net::IOBufferWithSize(buffer->size() + 1));
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  new_buffer->data()[0] = report_id;
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  memcpy(new_buffer->data() + 1, buffer->data(), buffer->size());
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return new_buffer;
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                       std::string dev_node)
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : HidConnection(device_info) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int flags = base::File::FLAG_OPEN |
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              base::File::FLAG_READ |
54e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              base::File::FLAG_WRITE;
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::File device_file(base::FilePath(dev_node), flags);
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!device_file.IsValid()) {
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::File::Error file_error = device_file.error_details();
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (file_error == base::File::FILE_ERROR_ACCESS_DENIED) {
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::File device_file(base::FilePath(dev_node), flags);
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (!device_file.IsValid()) {
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        LOG(ERROR) << device_file.error_details();
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        return;
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    } else {
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      LOG(ERROR) << file_error;
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return;
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (fcntl(device_file.GetPlatformFile(), F_SETFL,
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            fcntl(device_file.GetPlatformFile(), F_GETFL) | O_NONBLOCK)) {
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "Failed to set non-blocking flag to device file.";
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_file_ = device_file.Pass();
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_file_.GetPlatformFile(),
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::MessageLoopForIO::WATCH_READ_WRITE,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &device_file_watcher_,
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this)) {
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Failed to start watching device file.";
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::~HidConnectionLinux() {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Disconnect();
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(fd, device_file_.GetPlatformFile());
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uint8 buffer[1024] = {0};
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int bytes_read =
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      HANDLE_EINTR(read(device_file_.GetPlatformFile(), buffer, 1024));
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (bytes_read < 0) {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (errno == EAGAIN) {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Disconnect();
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  PendingHidReport report;
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  report.buffer = new net::IOBufferWithSize(bytes_read);
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  memcpy(report.buffer->data(), buffer, bytes_read);
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_reports_.push(report);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProcessReadQueue();
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {}
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Disconnect() {
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_file_watcher_.StopWatchingFileDescriptor();
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_file_.Close();
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while (!pending_reads_.empty()) {
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PendingHidRead pending_read = pending_reads_.front();
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_reads_.pop();
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_read.callback.Run(false, 0);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionLinux::Read(scoped_refptr<net::IOBufferWithSize> buffer,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const IOCallback& callback) {
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  PendingHidRead pending_read;
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_read.buffer = buffer;
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_read.callback = callback;
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_reads_.push(pending_read);
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProcessReadQueue();
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionLinux::Write(uint8_t report_id,
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               scoped_refptr<net::IOBufferWithSize> buffer,
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               const IOCallback& callback) {
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If report ID is non-zero, insert it into a new copy of the buffer.
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (report_id != 0)
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = CopyBufferWithReportId(buffer, report_id);
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int bytes_written = HANDLE_EINTR(
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      write(device_file_.GetPlatformFile(), buffer->data(), buffer->size()));
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (bytes_written < 0) {
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Disconnect();
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(true, bytes_written);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionLinux::GetFeatureReport(
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint8_t report_id,
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::IOBufferWithSize> buffer,
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const IOCallback& callback) {
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (buffer->size() == 0) {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The first byte of the destination buffer is the report ID being requested.
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  buffer->data()[0] = report_id;
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = ioctl(device_file_.GetPlatformFile(),
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     HIDIOCGFEATURE(buffer->size()),
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     buffer->data());
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result < 0)
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(false, 0);
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(true, result);
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionLinux::SendFeatureReport(
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint8_t report_id,
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::IOBufferWithSize> buffer,
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const IOCallback& callback) {
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (report_id != 0)
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = CopyBufferWithReportId(buffer, report_id);
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = ioctl(device_file_.GetPlatformFile(),
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     HIDIOCSFEATURE(buffer->size()),
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     buffer->data());
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result < 0)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(true, result);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::ProcessReadQueue() {
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while (pending_reads_.size() && pending_reports_.size()) {
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PendingHidRead read = pending_reads_.front();
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_reads_.pop();
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PendingHidReport report = pending_reports_.front();
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (report.buffer->size() > read.buffer->size()) {
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      read.callback.Run(false, report.buffer->size());
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pending_reports_.pop();
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      read.callback.Run(true, report.buffer->size());
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
211