blob: 0ed02670cecd92fdcaa8b3e0b63807a3b07d0891 [file] [log] [blame]
// Copyright 2018 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 <stdlib.h>
#include <utility>
#include <lib/fake_ddk/fake_ddk.h>
#include <unittest/unittest.h>
#include <zircon/assert.h>
namespace fake_ddk {
zx_device_t* kFakeDevice = reinterpret_cast<zx_device_t*>(0x55);
zx_device_t* kFakeParent = reinterpret_cast<zx_device_t*>(0xaa);
Bind* Bind::instance_ = nullptr;
Bind::Bind() {
ZX_ASSERT(!instance_);
instance_ = this;
}
bool Bind::Ok() {
BEGIN_HELPER;
EXPECT_TRUE(add_called_);
EXPECT_TRUE(remove_called_);
EXPECT_FALSE(bad_parent_);
EXPECT_FALSE(bad_device_);
END_HELPER;
}
void Bind::ExpectMetadata(const void* data, size_t data_length) {
metadata_ = data;
metadata_length_ = data_length;
}
void Bind::GetMetadataInfo(int* num_calls, size_t* length) {
*num_calls = add_metadata_calls_;
*length = metadata_length_;
}
void Bind::SetProtocols(fbl::Array<ProtocolEntry>&& protocols) {
protocols_ = std::move(protocols);
}
void Bind::SetSize(zx_off_t size) {
size_ = size;
}
void Bind::SetMetadata(const void* data, size_t data_length) {
get_metadata_ = data;
get_metadata_length_ = data_length;
}
zx_status_t Bind::DeviceAdd(zx_driver_t* drv, zx_device_t* parent,
device_add_args_t* args, zx_device_t** out) {
if (parent != kFakeParent) {
bad_parent_ = true;
}
*out = kFakeDevice;
add_called_ = true;
return ZX_OK;
}
zx_status_t Bind::DeviceRemove(zx_device_t* device) {
if (device != kFakeDevice) {
bad_device_ = true;
}
remove_called_ = true;
return ZX_OK;
}
zx_status_t Bind::DeviceAddMetadata(zx_device_t* device, uint32_t type, const void* data,
size_t length) {
if (device != kFakeDevice) {
bad_device_ = true;
}
if (metadata_) {
if (length != metadata_length_ || memcmp(data, metadata_, length) != 0) {
unittest_printf_critical("Unexpected metadata\n");
return ZX_ERR_BAD_STATE;
}
} else {
metadata_length_ += length;
}
add_metadata_calls_++;
return ZX_OK;
}
zx_status_t Bind::DeviceGetMetadata(zx_device_t* dev, uint32_t type, void* buf, size_t buflen,
size_t* actual) {
if (get_metadata_ == nullptr) {
return ZX_ERR_BAD_STATE;
}
*actual = get_metadata_length_;
if (buflen < get_metadata_length_) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
memcpy(buf, get_metadata_, get_metadata_length_);
get_metadata_calls_++;
return ZX_OK;
}
zx_status_t Bind::DeviceGetMetadataSize(zx_device_t* dev, uint32_t type, size_t* out_size) {
if (get_metadata_ == nullptr) {
return ZX_ERR_BAD_STATE;
}
*out_size = get_metadata_length_;
return ZX_OK;
}
void Bind::DeviceMakeVisible(zx_device_t* device) {
if (device != kFakeDevice) {
bad_device_ = true;
}
make_visible_called_ = true;
return;
}
zx_status_t Bind::DeviceGetProtocol(const zx_device_t* device, uint32_t proto_id, void* protocol) {
if (device != kFakeParent) {
bad_device_ = true;
return ZX_ERR_NOT_SUPPORTED;
}
auto out = reinterpret_cast<Protocol*>(protocol);
for (const auto& proto : protocols_) {
if (proto_id == proto.id) {
out->ops = proto.proto.ops;
out->ctx = proto.proto.ctx;
return ZX_OK;
}
}
return ZX_ERR_NOT_SUPPORTED;
}
const char* Bind::DeviceGetName(zx_device_t* device) {
if (device != kFakeParent) {
bad_device_ = true;
}
return "";
}
zx_off_t Bind::DeviceGetSize(zx_device_t* device) {
if (device != kFakeParent) {
bad_device_ = true;
}
return size_;
}
} // namespace fake_ddk
zx_status_t device_add_from_driver(zx_driver_t* drv, zx_device_t* parent,
device_add_args_t* args, zx_device_t** out) {
if (!fake_ddk::Bind::Instance()) {
return ZX_OK;
}
return fake_ddk::Bind::Instance()->DeviceAdd(drv, parent, args, out);
}
zx_status_t device_remove(zx_device_t* device) {
if (!fake_ddk::Bind::Instance()) {
return ZX_OK;
}
return fake_ddk::Bind::Instance()->DeviceRemove(device);
}
zx_status_t device_add_metadata(zx_device_t* device, uint32_t type, const void* data,
size_t length) {
if (!fake_ddk::Bind::Instance()) {
return ZX_OK;
}
return fake_ddk::Bind::Instance()->DeviceAddMetadata(device, type, data, length);
}
void device_make_visible(zx_device_t* device) {
if (fake_ddk::Bind::Instance()) {
fake_ddk::Bind::Instance()->DeviceMakeVisible(device);
}
return;
}
zx_status_t device_get_protocol(const zx_device_t* device, uint32_t proto_id, void* protocol) {
if (!fake_ddk::Bind::Instance()) {
return ZX_ERR_NOT_SUPPORTED;
}
return fake_ddk::Bind::Instance()->DeviceGetProtocol(device, proto_id, protocol);
}
const char* device_get_name(zx_device_t* device) {
if (!fake_ddk::Bind::Instance()) {
return nullptr;
}
return fake_ddk::Bind::Instance()->DeviceGetName(device);
}
zx_off_t device_get_size(zx_device_t* device) {
if (!fake_ddk::Bind::Instance()) {
return 0;
}
return fake_ddk::Bind::Instance()->DeviceGetSize(device);
}
zx_status_t device_get_metadata(zx_device_t* device, uint32_t type, void* buf, size_t buflen,
size_t* actual) {
if (!fake_ddk::Bind::Instance()) {
return ZX_ERR_NOT_SUPPORTED;
}
return fake_ddk::Bind::Instance()->DeviceGetMetadata(device, type, buf, buflen, actual);
}
zx_status_t device_get_metadata_size(zx_device_t* device, uint32_t type, size_t* out_size) {
if (!fake_ddk::Bind::Instance()) {
return ZX_ERR_NOT_SUPPORTED;
}
return fake_ddk::Bind::Instance()->DeviceGetMetadataSize(device, type, out_size);
}
extern "C" void driver_printf(uint32_t flags, const char* fmt, ...) {}
__WEAK zx_driver_rec __zircon_driver_rec__ = {};