blob: e74cd92099c2c1cea6d0c3f0b8d51517480e7610 [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 "src/devices/bin/driver_manager/inspect.h"
#include <lib/ddk/driver.h>
#include <lib/inspect/component/cpp/component.h>
#include <lib/inspect/component/cpp/service.h>
#include <utility>
#include "src/storage/lib/vfs/cpp/service.h"
#include "src/storage/lib/vfs/cpp/vfs_types.h"
#include "src/storage/lib/vfs/cpp/vnode.h"
namespace driver_manager {
namespace {
const char* BindParamName(uint32_t param_num) {
switch (param_num) {
case BIND_FLAGS:
return "Flags";
case BIND_PROTOCOL:
return "Protocol";
case BIND_AUTOBIND:
return "Autobind";
case BIND_PCI_VID:
return "PCI.VID";
case BIND_PCI_DID:
return "PCI.DID";
case BIND_PCI_CLASS:
return "PCI.Class";
case BIND_PCI_SUBCLASS:
return "PCI.Subclass";
case BIND_PCI_INTERFACE:
return "PCI.Interface";
case BIND_PCI_REVISION:
return "PCI.Revision";
case BIND_PCI_TOPO:
return "PCI.Topology";
case BIND_USB_VID:
return "USB.VID";
case BIND_USB_PID:
return "USB.PID";
case BIND_USB_CLASS:
return "USB.Class";
case BIND_USB_SUBCLASS:
return "USB.Subclass";
case BIND_USB_PROTOCOL:
return "USB.Protocol";
case BIND_PLATFORM_DEV_VID:
return "PlatDev.VID";
case BIND_PLATFORM_DEV_PID:
return "PlatDev.PID";
case BIND_PLATFORM_DEV_DID:
return "PlatDev.DID";
case BIND_ACPI_BUS_TYPE:
return "ACPI.BusType";
case BIND_IHDA_CODEC_VID:
return "IHDA.Codec.VID";
case BIND_IHDA_CODEC_DID:
return "IHDA.Codec.DID";
case BIND_IHDA_CODEC_MAJOR_REV:
return "IHDACodec.MajorRev";
case BIND_IHDA_CODEC_MINOR_REV:
return "IHDACodec.MinorRev";
case BIND_IHDA_CODEC_VENDOR_REV:
return "IHDACodec.VendorRev";
case BIND_IHDA_CODEC_VENDOR_STEP:
return "IHDACodec.VendorStep";
default:
return NULL;
}
}
} // namespace
zx::result<InspectDevfs> InspectDevfs::Create(async_dispatcher_t* dispatcher) {
InspectDevfs devfs(dispatcher);
return zx::ok(std::move(devfs));
}
zx::result<std::string> InspectDevfs::Publish(const char* name, zx::vmo vmo) {
if (dispatcher_ == nullptr) {
return zx::error(ZX_ERR_INVALID_ARGS);
}
std::string inspect_name = "driver-" + std::to_string(InspectDevfs::inspect_dev_counter_++) +
(name != nullptr ? "-" + std::string{name} : "");
// TODO(b/324637276): this is the export point for duplicated data from driver components.
inspect::PublishVmo(dispatcher_, std::move(vmo), {.tree_name = inspect_name});
return zx::ok(std::move(inspect_name));
}
InspectManager::InspectManager(async_dispatcher_t* dispatcher) : inspector_(dispatcher, {}) {
zx::result devfs = InspectDevfs::Create(dispatcher);
ZX_ASSERT(devfs.is_ok());
info_ = fbl::MakeRefCounted<Info>(root_node(), std::move(devfs.value()));
}
DeviceInspect InspectManager::CreateDevice(std::string name, zx::vmo vmo, uint32_t protocol_id) {
return DeviceInspect(info_, std::move(name), std::move(vmo), protocol_id);
}
DeviceInspect::DeviceInspect(fbl::RefPtr<InspectManager::Info> info, std::string name, zx::vmo vmo,
uint32_t protocol_id)
: info_(std::move(info)), protocol_id_(protocol_id), name_(std::move(name)) {
// Devices are sometimes passed bogus handles. Fun!
if (vmo.is_valid()) {
dev_vmo_.emplace(std::move(vmo));
}
device_node_ = info_->devices.CreateChild(name_);
// Increment device count.
info_->device_count.Add(1);
}
DeviceInspect::~DeviceInspect() {
if (info_) {
// Decrement device count.
info_->device_count.Subtract(1);
}
}
DeviceInspect DeviceInspect::CreateChild(std::string name, zx::vmo vmo, uint32_t protocol_id) {
return DeviceInspect(info_, std::move(name), std::move(vmo), protocol_id);
}
zx::result<> DeviceInspect::Publish() {
if (!dev_vmo_.has_value()) {
return zx::ok();
}
zx::result link_name = info_->devfs.Publish(name_.c_str(), std::move(*dev_vmo_));
dev_vmo_.reset();
if (link_name.is_error()) {
return link_name.take_error();
}
link_name_ = link_name.value();
return zx::ok();
}
void DeviceInspect::SetStaticValues(const std::string& topological_path, uint32_t protocol_id,
const std::string& type,
const cpp20::span<const zx_device_prop_t>& properties,
const std::string& driver_url) {
protocol_id_ = protocol_id;
device_node_.CreateString("topological_path", topological_path, &static_values_);
device_node_.CreateUint("protocol_id", protocol_id, &static_values_);
device_node_.CreateString("type", type, &static_values_);
device_node_.CreateString("driver", driver_url, &static_values_);
inspect::Node properties_array;
// Add a node only if there are any `props`
if (!properties.empty()) {
properties_array = device_node_.CreateChild("properties");
}
for (uint32_t i = 0; i < properties.size(); ++i) {
const zx_device_prop_t* p = &properties[i];
const char* param_name = BindParamName(p->id);
auto property = properties_array.CreateChild(std::to_string(i));
property.CreateUint("value", p->value, &static_values_);
if (param_name) {
property.CreateString("id", param_name, &static_values_);
} else {
property.CreateString("id", std::to_string(p->id), &static_values_);
}
static_values_.emplace(std::move(property));
}
// Place the node into value list as props will not change in the lifetime of the device.
if (!properties.empty()) {
static_values_.emplace(std::move(properties_array));
}
}
} // namespace driver_manager