blob: 476cd3066f03efa97b541322e984284d99c6e9b4 [file] [log] [blame]
// Copyright 2021 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.
#ifndef SRC_LIB_DDKTL_INCLUDE_DDKTL_METADATA_H_
#define SRC_LIB_DDKTL_INCLUDE_DDKTL_METADATA_H_
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/fidl/llcpp/message.h>
namespace ddk {
// Gets the raw metadata.
// Returns an error if metadata does not exist.
inline zx::status<std::vector<uint8_t>> GetMetadataBlob(zx_device_t* dev, uint32_t type) {
size_t metadata_size;
zx_status_t status = device_get_metadata_size(dev, type, &metadata_size);
if (status != ZX_OK) {
return zx::error(status);
}
std::vector<uint8_t> ret(metadata_size);
size_t actual;
status = device_get_metadata(dev, type, ret.data(), metadata_size, &actual);
if (status != ZX_OK || actual != metadata_size) {
return zx::error(status);
}
return zx::ok(std::move(ret));
}
// Gets a metadata that is contained in a specific struct.
// Checks that the size of the metadata corresponds to the struct size.
template <class T>
zx::status<std::unique_ptr<T>> GetMetadata(zx_device_t* dev, uint32_t type) {
auto metadata = GetMetadataBlob(dev, type);
if (!metadata.is_ok()) {
return metadata.take_error();
}
if (metadata->size() != sizeof(T)) {
zxlogf(ERROR, "Metadata size retrieved [%lu] does not match size of metadata struct [%lu]",
metadata->size(), sizeof(T));
return zx::error(ZX_ERR_INTERNAL);
}
return zx::ok(std::make_unique<T>(*reinterpret_cast<T*>(metadata->data())));
}
// Gets a metadata that is contained in an array of struct T.
// Checks that the size of the metadata corresponds to the struct size.
template <class T>
zx::status<std::vector<T>> GetMetadataArray(zx_device_t* dev, uint32_t type) {
auto metadata = GetMetadataBlob(dev, type);
if (!metadata.is_ok()) {
return metadata.take_error();
}
if ((metadata->size() % sizeof(T)) != 0) {
zxlogf(ERROR,
"Metadata size retrieved [%lu] was not an integer multiple of metadata struct [%lu]",
metadata->size(), sizeof(T));
return zx::error(ZX_ERR_INTERNAL);
}
auto mstart = reinterpret_cast<T*>(metadata->data());
return zx::ok(std::vector<T>(mstart, mstart + (metadata->size() / sizeof(T))));
}
template <typename T>
class DecodedMetadata {
public:
DecodedMetadata(std::vector<uint8_t> metadata_blob) {
metadata_blob_ = metadata_blob;
decoded_ = std::make_unique<fidl::unstable::DecodedMessage<T>>(
fidl::internal::WireFormatVersion::kV2, metadata_blob_.data(), metadata_blob_.size());
}
T* PrimaryObject() { return decoded_->PrimaryObject(); }
bool ok() { return decoded_->ok(); }
private:
std::vector<uint8_t> metadata_blob_;
std::unique_ptr<fidl::unstable::DecodedMessage<T>> decoded_;
};
// Gets metadata that is enoded in a specific fidl wire format.
// Decodes the metadata and returns a DecodedMetadata object, which stores the raw
// data as well as the decoded struct.
template <typename T>
zx::status<DecodedMetadata<T>> GetEncodedMetadata(zx_device_t* dev, uint32_t type) {
auto metadata = GetMetadataBlob(dev, type);
if (!metadata.is_ok()) {
return metadata.take_error();
}
DecodedMetadata<T> decoded(metadata.value());
if (!decoded.ok()) {
zxlogf(ERROR, "Failed to deserialize metadata.");
return zx::error(ZX_ERR_INTERNAL);
}
return zx::make_status(ZX_OK, std::move(decoded));
}
} // namespace ddk
#endif // SRC_LIB_DDKTL_INCLUDE_DDKTL_METADATA_H_