blob: e224992254e4bd1d456edd66192db8709c12cdef [file] [log] [blame]
// Copyright 2022 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 "src/devices/bin/driver_manager/v1/driver_development.h"
#include "src/devices/bin/driver_manager/composite_device.h"
namespace fdd = fuchsia_driver_development;
namespace fdm = fuchsia_device_manager;
zx::status<std::vector<fuchsia_driver_development::wire::DriverInfo>> GetDriverInfo(
fidl::AnyArena& allocator, const std::vector<const Driver*>& drivers) {
std::vector<fdd::wire::DriverInfo> driver_info_vec;
// TODO(fxbug.dev/80033): Support base drivers.
for (const auto& driver : drivers) {
fdd::wire::DriverInfo driver_info(allocator);
driver_info.set_name(allocator,
fidl::StringView(allocator, {driver->name.data(), driver->name.size()}));
driver_info.set_url(
allocator, fidl::StringView(allocator, {driver->libname.data(), driver->libname.size()}));
if (driver->bytecode_version == 1) {
auto* binding = std::get_if<std::unique_ptr<zx_bind_inst_t[]>>(&driver->binding);
if (!binding) {
return zx::error(ZX_ERR_NOT_FOUND);
}
auto binding_insts = binding->get();
uint32_t count = 0;
if (driver->binding_size > 0) {
count = driver->binding_size / sizeof(binding_insts[0]);
}
if (count > fdm::wire::kBindRulesInstructionsMax) {
return zx::error(ZX_ERR_BUFFER_TOO_SMALL);
}
using fdm::wire::BindInstruction;
fidl::VectorView<BindInstruction> instructions(allocator, count);
for (uint32_t i = 0; i < count; i++) {
instructions[i] = BindInstruction{
.op = binding_insts[i].op,
.arg = binding_insts[i].arg,
.debug = binding_insts[i].debug,
};
}
driver_info.set_bind_rules(
allocator, fdd::wire::BindRulesBytecode::WithBytecodeV1(allocator, instructions));
} else if (driver->bytecode_version == 2) {
auto* binding = std::get_if<std::unique_ptr<uint8_t[]>>(&driver->binding);
if (!binding) {
return zx::error(ZX_ERR_NOT_FOUND);
}
fidl::VectorView<uint8_t> bytecode(allocator, driver->binding_size);
for (uint32_t i = 0; i < driver->binding_size; i++) {
bytecode[i] = binding->get()[i];
}
driver_info.set_bind_rules(allocator,
fdd::wire::BindRulesBytecode::WithBytecodeV2(allocator, bytecode));
} else {
return zx::error(ZX_ERR_INVALID_ARGS);
}
driver_info_vec.push_back(std::move(driver_info));
}
return zx::ok(std::move(driver_info_vec));
}
zx::status<std::vector<fdd::wire::DeviceInfo>> GetDeviceInfo(
fidl::AnyArena& allocator, const std::vector<fbl::RefPtr<Device>>& devices) {
std::vector<fdd::wire::DeviceInfo> device_info_vec;
for (const auto& device : devices) {
if (device->props().size() > fdm::wire::kPropertiesMax) {
return zx::error(ZX_ERR_BUFFER_TOO_SMALL);
}
if (device->str_props().size() > fdm::wire::kPropertiesMax) {
return zx::error(ZX_ERR_BUFFER_TOO_SMALL);
}
fdd::wire::DeviceInfo device_info(allocator);
// id leaks internal pointers, but since this is a development only API, it shouldn't be
// a big deal.
device_info.set_id(allocator, reinterpret_cast<uint64_t>(device.get()));
// TODO(fxbug.dev/80094): Handle multiple parents case.
fidl::VectorView<uint64_t> parent_ids(allocator, 1);
parent_ids[0] = reinterpret_cast<uint64_t>(device->parent().get());
device_info.set_parent_ids(allocator, parent_ids);
size_t child_count = 0;
for (const auto& child __attribute__((unused)) : device->children()) {
child_count++;
}
if (child_count > 0) {
fidl::VectorView<uint64_t> child_ids(allocator, child_count);
size_t i = 0;
for (const auto& child : device->children()) {
child_ids[i++] = reinterpret_cast<uint64_t>(&child);
}
device_info.set_child_ids(allocator, child_ids);
}
if (device->host()) {
device_info.set_driver_host_koid(allocator, device->host()->koid());
}
char path[fdm::wire::kDevicePathMax + 1];
if (auto status = Coordinator::GetTopologicalPath(device, path, sizeof(path));
status != ZX_OK) {
return zx::error(status);
}
device_info.set_topological_path(allocator, fidl::StringView(allocator, {path, strlen(path)}));
device_info.set_bound_driver_libname(
allocator,
fidl::StringView(allocator, {device->libname().data(), device->libname().size()}));
fidl::VectorView<fdm::wire::DeviceProperty> props(allocator, device->props().size());
for (size_t i = 0; i < device->props().size(); i++) {
const auto& prop = device->props()[i];
props[i] = fdm::wire::DeviceProperty{
.id = prop.id,
.reserved = prop.reserved,
.value = prop.value,
};
}
fidl::VectorView<fdm::wire::DeviceStrProperty> str_props(allocator, device->str_props().size());
for (size_t i = 0; i < device->str_props().size(); i++) {
const auto& str_prop = device->str_props()[i];
if (str_prop.value.valueless_by_exception()) {
return zx::error(ZX_ERR_INVALID_ARGS);
}
auto fidl_str_prop = fdm::wire::DeviceStrProperty{
.key = fidl::StringView(allocator, str_prop.key),
};
switch (str_prop.value.index()) {
case StrPropValueType::Integer: {
const auto prop_val = std::get<StrPropValueType::Integer>(str_prop.value);
fidl_str_prop.value = fdm::wire::PropertyValue::WithIntValue(prop_val);
break;
}
case StrPropValueType::String: {
const auto prop_val = std::get<StrPropValueType::String>(str_prop.value);
fidl_str_prop.value = fdm::wire::PropertyValue::WithStrValue(
allocator, fidl::StringView(allocator, prop_val));
break;
}
case StrPropValueType::Bool: {
const auto prop_val = std::get<StrPropValueType::Bool>(str_prop.value);
fidl_str_prop.value = fdm::wire::PropertyValue::WithBoolValue(prop_val);
break;
}
case StrPropValueType::Enum: {
const auto prop_val = std::get<StrPropValueType::Enum>(str_prop.value);
fidl_str_prop.value = fdm::wire::PropertyValue::WithEnumValue(
allocator, fidl::StringView(allocator, prop_val));
break;
}
}
str_props[i] = fidl_str_prop;
}
device_info.set_property_list(allocator, fdm::wire::DevicePropertyList{
.props = props,
.str_props = str_props,
});
device_info.set_flags(fdd::wire::DeviceFlags::TruncatingUnknown(device->flags));
device_info_vec.push_back(std::move(device_info));
}
return zx::ok(std::move(device_info_vec));
}