blob: 41ea8cfc6c36bf48d604f05cd7060ee24cdaecc7 [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.
library fuchsia.driver.framework;
using fuchsia.device.fs;
using fuchsia.component;
using fuchsia.component.decl;
using fuchsia.io;
using zx;
alias NodePropertyKeyString = string:256;
alias NodePropertyKeyUint = uint32;
alias NodePropertyValueUint = uint32;
alias NodePropertyValueString = string:256;
alias NodePropertyValueBool = bool;
alias NodePropertyValueEnum = string:256;
const MAX_OFFER_COUNT uint32 = fuchsia.component.MAX_DYNAMIC_OFFER_COUNT;
const MAX_SYMBOL_COUNT uint8 = 64;
const MAX_PROPERTY_COUNT uint8 = 64;
const MAX_NODE_NAME_LENGTH uint8 = 128;
const MAX_SYMBOL_NAME_LENGTH uint8 = 128;
@available(added=18)
const MAX_RESOURCE_NAME_LENGTH uint8 = 128;
alias NodePropertyVector = vector<NodeProperty>:MAX_PROPERTY_COUNT;
alias NodeName = string:MAX_NODE_NAME_LENGTH;
/// Definition of a symbol provided by a driver for a node. A symbol is local to
/// a driver host.
type NodeSymbol = table {
/// Name of the symbol.
1: name string:MAX_SYMBOL_NAME_LENGTH;
/// Virtual address of the symbol, within a driver host's process.
2: address uint64;
};
type NodePropertyKey = strict union {
1: int_value NodePropertyKeyUint;
2: string_value NodePropertyKeyString;
};
type NodePropertyValue = flexible union {
1: int_value NodePropertyValueUint;
2: string_value NodePropertyValueString;
3: bool_value NodePropertyValueBool;
4: enum_value NodePropertyValueEnum;
};
/// Definition of a property for a node. A property is commonly used to match a
/// node to a driver for driver binding.
type NodeProperty = struct {
/// Key for the property.
key NodePropertyKey;
/// Value for the property.
value NodePropertyValue;
};
@available(added=18)
type Offer = flexible union {
1: zircon_transport fuchsia.component.decl.Offer;
2: driver_transport fuchsia.component.decl.Offer;
};
// Arguments for adding a node to the devfs filesystem.
type DevfsAddArgs = resource table {
/// This is the connector to be installed in devfs.
/// `Connect()` will be called when a client connects to this node in the filesystem.
/// Optional: If this is not provided then an empty node will appear in devfs.
1: connector client_end:fuchsia.device.fs.Connector;
/// This is the class name for installing this node in devfs.
/// The node will be placed within /dev/class/{class_name}.
/// If `class_name` does not exist under /dev/class/ it will be created.
/// Optional: If this is not provided then the node will only be added via topological path.
2: class_name string:fuchsia.io.MAX_NAME_LENGTH;
/// This is a vmo of inspect data that will be installed in devfs.
/// Optional: If this is not provided then the devfs's inspect data will be empty.
3: inspect zx.Handle:VMO;
/// The connection types that are supported by the |connector| given.
/// The driver framework should handle connection types that are not supported by the
/// connector.
/// If not provided, only the device type is assumed as supported by the connector.
@available(added=16)
4: connector_supports fuchsia.device.fs.ConnectionType;
/// This is the controller connector to be installed in devfs.
/// `Connect()` will be called when a client connects to the device_controller connection
/// for this node in the filesystem.
/// Optional: If this is not provided then the Node will handle the connection natively.
/// This option should only be used by the compat shim or in tests
@available(added=HEAD)
5: controller_connector client_end:fuchsia.device.fs.Connector;
};
/// Arguments for adding a node.
type NodeAddArgs = resource table {
/// Name of the node.
1: name NodeName;
/// Capabilities to offer to the driver that is bound to this node.
/// The driver must ensure these capabilities are added to its outgoing directory
/// before adding the child node.
@available(
deprecated=18,
removed=19,
legacy=true,
note="Replaced with 'offers2' which can carry the transport type.")
2: offers vector<fuchsia.component.decl.Offer>:MAX_OFFER_COUNT;
/// Functions to provide to the driver that is bound to this node.
3: symbols vector<NodeSymbol>:MAX_SYMBOL_COUNT;
/// Properties of the node.
4: properties NodePropertyVector;
/// The arguments for how this node should be added to devfs.
5: devfs_args DevfsAddArgs;
/// Capabilities to offer to the driver that is bound to this node.
/// The driver must ensure these capabilities are added to its outgoing directory
/// before adding the child node.
@available(added=18)
6: offers2 vector<Offer>:MAX_OFFER_COUNT;
};
/// Protocol through which a parent node controls one of its children.
open protocol NodeController {
/// Removes the node and all of its children.
flexible Remove();
/// Request that the framework attempts to bind a driver to this node.
/// This is an *additional* request for binding as the framework attempts to bind a node once
/// when the node is created.
/// * error `ZX_ERR_ALREADY_BOUND` if the node is already bound and `force_rebind` is false.
/// * error `ZX_ERR_ALREADY_EXISTS` if the node has an outstanding |RequestBind| call which has
/// not completed.
flexible RequestBind(table {
/// If this is true, then the node unbinds from its matched driver before it attempts to
/// bind through the normal bind process.
1: force_rebind bool;
/// If this is set, then only drivers matching this URL suffix will be considered in
/// binding.
/// E.g: "gpt.cm", "meta/gpt.cm", "fuchsia-boot:///#meta/gpt.cm".
2: driver_url_suffix string:MAX;
}) -> () error zx.Status;
/// Event that is triggered when the associated `Node` is bound to a driver.
flexible -> OnBind();
};
/// Error codes for the Node protocol.
type NodeError = flexible enum {
// An internal error occurred.
INTERNAL = 1;
// The Node was removed from the topology.
NODE_REMOVED = 2;
// The Node's name is missing.
NAME_MISSING = 3;
/// The Node's name is invalid. Specifically, it must not contain a period
/// in its name.
NAME_INVALID = 4;
/// A sibling Node exists with the same name.
NAME_ALREADY_EXISTS = 5;
/// An offer for this Node is missing a source name.
OFFER_SOURCE_NAME_MISSING = 6;
/// An offer for this Node should not have a source or target.
OFFER_REF_EXISTS = 7;
/// A symbol for this Node is missing a name.
SYMBOL_NAME_MISSING = 8;
/// A symbol for this Node is missing an address.
SYMBOL_ADDRESS_MISSING = 9;
/// There is another symbol for this Node with the same name.
SYMBOL_ALREADY_EXISTS = 10;
/// The node is in the process of unbinding all of its children.
@available(added=20)
UNBIND_CHILDREN_IN_PROGRESS = 11;
};
/// Protocol through which a driver manages a node that it is bound to.
/// Drivers should maintain their client connection to the node. Dropping
/// the client connection while the driver is running will cause the
/// driver framework to remove the driver and node from the topology.
/// If the driver has set `host_restart_on_crash` to "true" in their
/// component manifest, dropping the connection will initiate a restart of
/// the driver host and driver.
open protocol Node {
/// Adds a child node to this node.
///
/// If `node` is present, this driver takes responsibility for binding to
/// the newly created child. Otherwise, the driver framework will locate an
/// appropriate driver to bind the child to.
flexible AddChild(resource struct {
args NodeAddArgs;
controller server_end:NodeController;
node server_end:<Node, optional>;
}) -> () error NodeError;
};