blob: 298e43f0c3f0643760c4d16aa6aad9ce7749d4c2 [file] [log] [blame]
// Copyright 2018 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.
#ifndef CECSERVICE_CEC_FD_H_
#define CECSERVICE_CEC_FD_H_
#include <linux/cec.h>
#include <memory>
#include <base/callback.h>
#include <base/macros.h>
#include <base/memory/weak_ptr.h>
#include <base/files/file_path.h>
#include <base/files/scoped_file.h>
#include <brillo/message_loops/message_loop.h>
namespace cecservice {
// Wrapper around CEC device file descriptor, interface to enable unit testing.
class CecFd {
public:
// Types of events that can occur on the FD.
enum class EventType {
kPriorityRead, // Priority data can be read.
kRead, // Regular data available for reading.
kWrite, // Data can be written.
};
// Callback used to notify about events occurring on the FD.
using Callback = base::Callback<void(EventType)>;
// Result of transmit operation.
enum class TransmitResult {
kOk, // Operation succeeded.
kNoNet, // Operation failed, ENONET reported.
kBusy, // Operation failed, no space in output buffer.
kInvalidValue, // Operation failed, EINVAL reported.
kError, // Operation failed, not recoverable error.
};
virtual ~CecFd() = default;
// Sets logical addresses of the device, returns false if the operation
// failed. This is just a wrapper around CEC_ADAP_S_LOG_ADDR ioctl.
virtual bool SetLogicalAddresses(struct cec_log_addrs* addresses) const = 0;
// Gets logical addresses of the device, returns false if the operation
// failed. This is just a wrapper around CEC_ADAP_G_LOG_ADDRS ioctl.
virtual bool GetLogicalAddresses(struct cec_log_addrs* addresses) const = 0;
// Receives message, returns false if the operation failed. This is just a
// wrapper around CEC_RECEIVE ioctl.
virtual bool ReceiveMessage(struct cec_msg* message) const = 0;
// Receives pending event, returns false if the operation failed. This is just
// a wrapper around CEC_DQEVENT ioctl.
virtual bool ReceiveEvent(struct cec_event* event) const = 0;
// Transmits message, a wrapper around CEC_TRANSMIT ioctl.
virtual TransmitResult TransmitMessage(struct cec_msg* message) const = 0;
// Obtains device capabilities, returns false if the operation failed. This is
// just a wrapper around CEC_ADAP_G_CAPS ioctl.
virtual bool GetCapabilities(struct cec_caps* capabilities) const = 0;
// Sets device mode. Returns false if the operation failed, wrapper around
// CEC_S_MODE ioctl.
virtual bool SetMode(uint32_t mode) const = 0;
// Sets a callback to be called when an event occurs on the FD. The
// callback is always invoked when regular and priority data arrive (events).
// Also, the callback is called when watching for write readiness has been
// requested via WriteWatch method. This operation should be only performed
// once during lifetime of the object. Returns false if the operation fails.
virtual bool SetEventCallback(const Callback& callback) = 0;
// Starts watching descriptor for write readiness. It is one off request.
// Returns false if the operation fails.
virtual bool WriteWatch() = 0;
};
// Actual implementation of CEC file descriptor.
class CecFdImpl : public CecFd {
public:
explicit CecFdImpl(base::ScopedFD fd, base::ScopedFD epoll_fd);
~CecFdImpl() override;
// CecFd overrides:
bool SetLogicalAddresses(struct cec_log_addrs* addresses) const override;
bool GetLogicalAddresses(struct cec_log_addrs* addresses) const override;
bool ReceiveMessage(struct cec_msg* message) const override;
bool ReceiveEvent(struct cec_event* event) const override;
TransmitResult TransmitMessage(struct cec_msg* message) const override;
bool GetCapabilities(struct cec_caps* capabilities) const override;
bool SetMode(uint32_t mode) const override;
bool SetEventCallback(const Callback& callback) override;
bool WriteWatch() override;
private:
void OnPriorityDataReady();
void OnDataReady();
void OnWriteReady();
// Actual FD of the opened device.
base::ScopedFD fd_;
// Additional epoll FD used to wait for POLLPRI data.
base::ScopedFD epoll_fd_;
const brillo::MessageLoop::TaskId kTaskIdNull =
brillo::MessageLoop::kTaskIdNull;
brillo::MessageLoop::TaskId priority_taskid_ = kTaskIdNull;
brillo::MessageLoop::TaskId read_taskid_ = kTaskIdNull;
brillo::MessageLoop::TaskId write_taskid_ = kTaskIdNull;
Callback callback_;
base::WeakPtrFactory<CecFdImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(CecFdImpl);
};
// Utility class to open files, for unit testing.
class CecFdOpener {
public:
virtual ~CecFdOpener() = default;
// Open file, flags argument is passed directly to the open(2) syscall.
virtual std::unique_ptr<CecFd> Open(const base::FilePath& path,
int flags) const = 0;
};
// Actual implementation of CecFdOpener.
class CecFdOpenerImpl : public CecFdOpener {
public:
CecFdOpenerImpl();
~CecFdOpenerImpl() override;
// CecFdOpener:
std::unique_ptr<CecFd> Open(const base::FilePath& path,
int flags) const override;
private:
DISALLOW_COPY_AND_ASSIGN(CecFdOpenerImpl);
};
} // namespace cecservice
#endif // CECSERVICE_CEC_FD_H_