blob: 526cbf0a74f7073216dfef3f3b0ae209040594be [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 <fuchsia/hardware/registers/llcpp/fidl.h>
#include <map>
#include <queue>
#include <ddktl/protocol/registers.h>
namespace mock_registers {
// Mock Registers. FIDL implementation.
class MockRegisters : public ::llcpp::fuchsia::hardware::registers::Device::Interface {
public:
explicit MockRegisters(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
~MockRegisters() {}
// Manage the Fake FIDL Message Loop
zx_status_t Init(zx::channel remote) {
auto result = fidl::BindServer(dispatcher_, std::move(remote), this);
return result.is_ok() ? ZX_OK : result.error();
}
template <typename T>
void ExpectRead(uint64_t offset, T mask, T value) {
static_assert(std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> ||
std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t>);
GetExpectRead<T>()[offset].push(std::pair<T, T>(mask, value));
}
template <typename T>
void ExpectWrite(uint64_t offset, T mask, T value) {
static_assert(std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> ||
std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t>);
GetExpectWrite<T>()[offset].push(std::pair<T, T>(mask, value));
}
inline zx_status_t VerifyAll();
private:
// Implement Registers FIDL Protocol.
void ReadRegister8(uint64_t offset, uint8_t mask, ReadRegister8Completer::Sync& completer) {
ReadRegister(offset, mask, completer);
}
void ReadRegister16(uint64_t offset, uint16_t mask, ReadRegister16Completer::Sync& completer) {
ReadRegister(offset, mask, completer);
}
void ReadRegister32(uint64_t offset, uint32_t mask, ReadRegister32Completer::Sync& completer) {
ReadRegister(offset, mask, completer);
}
void ReadRegister64(uint64_t offset, uint64_t mask, ReadRegister64Completer::Sync& completer) {
ReadRegister(offset, mask, completer);
}
void WriteRegister8(uint64_t offset, uint8_t mask, uint8_t value,
WriteRegister8Completer::Sync& completer) {
WriteRegister(offset, mask, value, completer);
}
void WriteRegister16(uint64_t offset, uint16_t mask, uint16_t value,
WriteRegister16Completer::Sync& completer) {
WriteRegister(offset, mask, value, completer);
}
void WriteRegister32(uint64_t offset, uint32_t mask, uint32_t value,
WriteRegister32Completer::Sync& completer) {
WriteRegister(offset, mask, value, completer);
}
void WriteRegister64(uint64_t offset, uint64_t mask, uint64_t value,
WriteRegister64Completer::Sync& completer) {
WriteRegister(offset, mask, value, completer);
}
// Helper functions for FIDL
template <typename T, typename Completer>
void ReadRegister(uint64_t offset, T mask, Completer& completer) {
auto& expect_read = GetExpectRead<T>()[offset];
if (expect_read.empty()) {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
return;
}
auto value = expect_read.front();
expect_read.pop();
if (value.first == mask) {
completer.ReplySuccess(static_cast<T>(value.second));
} else {
completer.ReplyError(ZX_ERR_INVALID_ARGS);
}
}
template <typename T, typename Completer>
void WriteRegister(uint64_t offset, T mask, T value, Completer& completer) {
auto& expect_write = GetExpectWrite<T>()[offset];
if (expect_write.empty()) {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
return;
}
auto expected_value = expect_write.front();
expect_write.pop();
if ((expected_value.first == mask) && (expected_value.second == value)) {
completer.ReplySuccess();
} else {
completer.ReplyError(ZX_ERR_INVALID_ARGS);
}
}
// Helper functions to get queues.
template <typename T>
auto& GetExpectRead() {
if constexpr (!std::is_same_v<T, uint64_t>) {
return expect_read64;
} else if constexpr (!std::is_same_v<T, uint32_t>) {
return expect_read32;
} else if constexpr (!std::is_same_v<T, uint16_t>) {
return expect_read16;
} else if constexpr (!std::is_same_v<T, uint8_t>) {
return expect_read8;
}
}
template <typename T>
auto& GetExpectWrite() {
if constexpr (!std::is_same_v<T, uint64_t>) {
return expect_write64;
} else if constexpr (!std::is_same_v<T, uint32_t>) {
return expect_write32;
} else if constexpr (!std::is_same_v<T, uint16_t>) {
return expect_write16;
} else if constexpr (!std::is_same_v<T, uint8_t>) {
return expect_write8;
}
}
async_dispatcher_t* dispatcher_;
std::map<uint64_t, std::queue<std::pair<uint8_t, uint8_t>>> expect_read8;
std::map<uint64_t, std::queue<std::pair<uint16_t, uint16_t>>> expect_read16;
std::map<uint64_t, std::queue<std::pair<uint32_t, uint32_t>>> expect_read32;
std::map<uint64_t, std::queue<std::pair<uint64_t, uint64_t>>> expect_read64;
std::map<uint64_t, std::queue<std::pair<uint8_t, uint8_t>>> expect_write8;
std::map<uint64_t, std::queue<std::pair<uint16_t, uint16_t>>> expect_write16;
std::map<uint64_t, std::queue<std::pair<uint32_t, uint32_t>>> expect_write32;
std::map<uint64_t, std::queue<std::pair<uint64_t, uint64_t>>> expect_write64;
};
// Mock Registers Device implementing Banjo protocol to connect to FIDL implementation.
class MockRegistersDevice : public ddk::RegistersProtocol<MockRegistersDevice> {
public:
MockRegistersDevice(async_dispatcher_t* dispatcher)
: proto_({&registers_protocol_ops_, this}), fidl_service_(dispatcher) {}
void RegistersConnect(zx::channel chan) { fidl_service_.Init(std::move(chan)); }
const registers_protocol_t* proto() const { return &proto_; }
MockRegisters* fidl_service() { return &fidl_service_; }
private:
registers_protocol_t proto_;
MockRegisters fidl_service_;
};
zx_status_t MockRegisters::VerifyAll() {
for (const auto& expect_read : GetExpectRead<uint8_t>()) {
if (!expect_read.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_read : GetExpectRead<uint16_t>()) {
if (!expect_read.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_read : GetExpectRead<uint32_t>()) {
if (!expect_read.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_read : GetExpectRead<uint64_t>()) {
if (!expect_read.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_write : GetExpectWrite<uint8_t>()) {
if (!expect_write.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_write : GetExpectWrite<uint16_t>()) {
if (!expect_write.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_write : GetExpectWrite<uint32_t>()) {
if (!expect_write.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
for (const auto& expect_write : GetExpectWrite<uint64_t>()) {
if (!expect_write.second.empty()) {
return ZX_ERR_INTERNAL;
}
}
return ZX_OK;
}
} // namespace mock_registers