blob: 3bb7208ee3df30214aff2d7f905210ee0e697b92 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "hid_connection.h"
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/posix/safe_strerror.h>
namespace atrusctl {
bool HIDConnection::Open(const std::string& path) {
int descriptor = HANDLE_EINTR(open(path.c_str(), O_RDWR));
if (descriptor < 0) {
PLOG(ERROR) << path;
return false;
}
fd_.reset(descriptor);
return true;
}
void HIDConnection::Close() {
if (fd_.is_valid()) {
fd_.reset();
}
}
// Monitors the file descriptor |fd_| for when it becomes ready for read
// operations. This is done by passing |fd_| through |readset| to the second
// argument of select() (see manpage for select(2) for more details).
// We use a timeout of 2 seconds, after that we assume that the device is
// unresponsive and that there is no read operation possible at the time.
//
// If select() is interrupted by a signal handler (and returns EINTR), we want
// to retry the operation. Since select() modifies the timeout structure
// |tv| when this happens, we need to reset it before each retry. Hence the
// do-while loop.
bool HIDConnection::WaitUntilReadable(bool* timeout) const {
DCHECK(fd_.is_valid());
*timeout = false;
fd_set readset;
struct timeval tv;
int retval;
do {
FD_ZERO(&readset);
FD_SET(fd_.get(), &readset);
tv.tv_sec = 2;
tv.tv_usec = 200000;
retval = select(fd_.get() + 1, &readset, NULL, NULL, &tv);
if ((retval < 0) && (errno != EINTR)) {
PLOG(ERROR) << "select";
return false;
}
if (retval == 0) {
*timeout = true;
return false;
}
} while ((retval < 0) && (errno == EINTR));
return true;
}
bool HIDConnection::Write(const std::vector<uint8_t>& buffer) const {
DCHECK(fd_.is_valid());
ssize_t size_written = write(fd_.get(), buffer.data(), buffer.size());
if (size_written < 0) {
PLOG(ERROR) << "write";
return false;
}
return true;
}
bool HIDConnection::Read(std::vector<uint8_t>* buffer,
size_t buffer_size) const {
DCHECK(fd_.is_valid());
CHECK(buffer);
buffer->resize(buffer_size);
ssize_t size_read = read(fd_.get(), buffer->data(), buffer->size());
if (size_read < 0) {
PLOG(ERROR) << "read";
return false;
}
return true;
}
} // namespace atrusctl