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