hid_connection_linux.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/message_loop/message_loop.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/posix/eintr_wrapper.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tuple.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service.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) {
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int flags = base::File::FLAG_OPEN |
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              base::File::FLAG_READ |
52e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              base::File::FLAG_WRITE;
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::File device_file(base::FilePath(dev_node), flags);
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!device_file.IsValid()) {
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::File::Error file_error = device_file.error_details();
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (file_error == base::File::FILE_ERROR_ACCESS_DENIED) {
596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      VLOG(1) << "Access denied opening device read-write, trying read-only.";
606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      device_file = base::File(base::FilePath(dev_node), flags);
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!device_file.IsValid()) {
676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    LOG(ERROR) << "Failed to open '" << dev_node << "': "
686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        << base::File::ErrorToString(device_file.error_details());
696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (fcntl(device_file.GetPlatformFile(), F_SETFL,
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            fcntl(device_file.GetPlatformFile(), F_GETFL) | O_NONBLOCK)) {
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PLOG(ERROR) << "Failed to set non-blocking flag to device file";
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_file_ = device_file.Pass();
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_file_.GetPlatformFile(),
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      true,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::MessageLoopForIO::WATCH_READ_WRITE,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &device_file_watcher_,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this)) {
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Failed to start watching device file.";
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::~HidConnectionLinux() {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Disconnect();
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Flush();
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::PlatformRead(
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<net::IOBufferWithSize> buffer,
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const IOCallback& callback) {
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  PendingHidRead pending_read;
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_read.buffer = buffer;
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_read.callback = callback;
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_reads_.push(pending_read);
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProcessReadQueue();
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::PlatformWrite(
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    uint8_t report_id,
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<net::IOBufferWithSize> buffer,
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const IOCallback& callback) {
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Linux always expects the first byte of the buffer to be the report ID.
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  buffer = CopyBufferWithReportId(buffer, report_id);
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int bytes_written = HANDLE_EINTR(
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      write(device_file_.GetPlatformFile(), buffer->data(), buffer->size()));
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (bytes_written < 0) {
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VPLOG(1) << "Write failed";
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Disconnect();
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (bytes_written != buffer->size()) {
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(WARNING) << "Incomplete HID write: "
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   << bytes_written << " != " << buffer->size();
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    callback.Run(true, bytes_written == 0 ? 0 : bytes_written - 1);
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::PlatformGetFeatureReport(
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint8_t report_id,
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::IOBufferWithSize> buffer,
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const IOCallback& callback) {
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (buffer->size() == 0) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The first byte of the destination buffer is the report ID being requested.
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  buffer->data()[0] = report_id;
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = ioctl(device_file_.GetPlatformFile(),
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     HIDIOCGFEATURE(buffer->size()),
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     buffer->data());
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (result < 0) {
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VPLOG(1) << "Failed to get feature report";
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(false, 0);
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(true, result);
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::PlatformSendFeatureReport(
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint8_t report_id,
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::IOBufferWithSize> buffer,
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const IOCallback& callback) {
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (report_id != 0)
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = CopyBufferWithReportId(buffer, report_id);
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = ioctl(device_file_.GetPlatformFile(),
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     HIDIOCSFEATURE(buffer->size()),
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     buffer->data());
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (result < 0) {
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VPLOG(1) << "Failed to send feature report";
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false, 0);
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(true, result);
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(thread_checker().CalledOnValidThread());
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(fd, device_file_.GetPlatformFile());
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uint8 raw_buffer[1024] = {0};
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int bytes_read =
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      HANDLE_EINTR(read(device_file_.GetPlatformFile(), raw_buffer, 1024));
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (bytes_read < 0) {
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (errno == EAGAIN) {
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return;
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VPLOG(1) << "Read failed";
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Disconnect();
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<net::IOBufferWithSize> buffer =
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new net::IOBufferWithSize(bytes_read);
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  memcpy(buffer->data(), raw_buffer, bytes_read);
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ProcessInputReport(buffer);
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::Disconnect() {
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(thread_checker().CalledOnValidThread());
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  device_file_watcher_.StopWatchingFileDescriptor();
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  device_file_.Close();
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Flush();
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::Flush() {
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (!pending_reads_.empty()) {
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pending_reads_.front().callback.Run(false, 0);
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pending_reads_.pop();
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionLinux::ProcessInputReport(
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<net::IOBufferWithSize> buffer) {
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(thread_checker().CalledOnValidThread());
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  PendingHidReport report;
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  report.buffer = buffer;
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pending_reports_.push(report);
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ProcessReadQueue();
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::ProcessReadQueue() {
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(thread_checker().CalledOnValidThread());
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while (pending_reads_.size() && pending_reports_.size()) {
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PendingHidRead read = pending_reads_.front();
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PendingHidReport report = pending_reports_.front();
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (read.buffer->size() < report.buffer->size()) {
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      read.callback.Run(false, 0);
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pending_reads_.pop();
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pending_reports_.pop();
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (CompleteRead(report.buffer, read.callback)) {
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        pending_reads_.pop();
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
235