blob: eeb1e1dd91d4bc03f455d1efc211a9e5ef4b39ec [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.
library fuchsia.device.manager;
// TODO(teisenbe): Move these interfaces to be internal to the devmgr codebase
using zx;
/// This has the same structure as zx_device_prop_t.
struct DeviceProperty {
uint16 id;
uint16 reserved;
uint32 value;
// TODO(bwb): Make this descriptive of binding, not zx_bind_inst_t
// currently a magic bitfield defined in binding.h
struct BindInstruction {
/// bitfield that encodes the operation and execution conditions
uint32 op;
/// bitfield that encodes the arguments
uint32 arg;
/// bitfield that encodes debugging information
uint32 debug;
// Identifier used to let the devcoordinator describe specific devices during
// composite construction
using LocalDeviceId = uint64;
/// This definition must match `ZX_DEVICE_NAME_MAX` and is checked by a static assert.
const uint32 DEVICE_NAME_MAX = 31;
/// Maximum number of bytes in a path
// The simple name PATH_MAX collides with a musl #define on c++ bindings.
const uint32 DEVICE_PATH_MAX = 1024;
/// Maximum number of bytes in a device arguments string.
const uint32 DEVICE_ARGS_MAX = 1024;
/// Maximum number of bytes in a metadata payload
const uint32 METADATA_BYTES_MAX = 8192;
/// Maximum number of metadata that can be added to a device
const uint32 METADATA_MAX = 32;
/// Maximum number of properties that can be attached to a device
const uint32 PROPERTIES_MAX = 256;
/// Maximum number of fragments that a composite device can have
const uint32 FRAGMENTS_MAX = 16;
/// Maximum number of parts that a composite device fragment can have
const uint32 DEVICE_FRAGMENT_PARTS_MAX = 16;
/// Maximum number of instructions in the match program of a device fragment part
// Maximum number of instructions in a driver bind program
/// Bit flags for device add configuration
bits AddDeviceConfig : uint32 {
/// Device can be a fragment in multiple composite devices
/// Device should be marked invisible initially (used for deprecated DEVICE_ADD_INVISIBLE)
INVISIBLE = 0x00000002;
/// Device should not trigger the auto-bind mechanism
SKIP_AUTOBIND = 0x00000004;
/// A part of a description of a DeviceFragment
struct DeviceFragmentPart {
// This is an awful hack around the LLCPP bindings not being ready yet.
// Since we're using the C ones for now, we can only embed these structures as
// arrays instead of vectors.
uint32 match_program_count;
array<BindInstruction>:DEVICE_FRAGMENT_PART_INSTRUCTIONS_MAX match_program;
/// A piece of a composite device
struct DeviceFragment {
// This is an awful hack around the LLCPP bindings not being ready yet.
// Since we're using the C ones for now, we can only embed these structures as
// arrays instead of vectors.
string:32 name;
uint32 parts_count;
array<DeviceFragmentPart>:DEVICE_FRAGMENT_PARTS_MAX parts;
/// Metadata that can be added to a device
struct DeviceMetadata {
uint32 key;
vector<uint8>:METADATA_BYTES_MAX data;
/// Composite device parts and properties
struct CompositeDeviceDescriptor {
vector<DeviceProperty>:PROPERTIES_MAX props;
vector<DeviceFragment>:FRAGMENTS_MAX fragments;
uint32 coresident_device_index;
vector<DeviceMetadata>:METADATA_MAX? metadata;
/// A enum of CompatibilityTestStatus
enum CompatibilityTestStatus : uint32 {
OK = 1;
/// Protocol for controlling devices in a devhost process from the devcoordinator
protocol DeviceController {
/// Bind the requested driver to this device. `driver_path` is informational,
/// but all calls to BindDriver/CreateDevice should use the same `driver_path`
/// each time they use a `driver` VMO with the same contents. Returns a `status`
/// and optionally a channel to the driver's test output. `test_output` will be
/// not present unless the driver is configured to run its run_unit_tests hook, in
/// which case the other end of the channel will have been passed to the driver.
BindDriver(string:DEVICE_PATH_MAX driver_path, zx.handle:VMO driver)
-> (zx.status status, zx.handle:CHANNEL? test_output);
/// Give this device a channel to its shadow in another process.
ConnectProxy(zx.handle:CHANNEL shadow);
/// Ask devhost to call the device init hook.
Init() -> (zx.status status);
/// Ask devhost to unbind this device. On success, the remote end of this
/// interface channel will close instead of returning a result.
Unbind() -> () error zx.status;
/// Ask the devhost to complete the removal of this device, which previously had
/// invoked `ScheduleRemove`. This is a special case that can be removed
/// once `device_remove` invokes `unbind`.
CompleteRemoval() -> () error zx.status;
/// Ask devhost to suspend this device, using the target state indicated by `flags`.
Suspend(uint32 flags) -> (zx.status status);
/// Ask devhost to resume this device, using the target system state indicated by
/// 'target_system_state'.
Resume(uint32 target_system_state) -> (zx.status status);
/// Inform devhost about the compatibility test status when compatibility tests
/// fail or complete successfully.
// TODO(ravoorir) : This should be an asynchronous call from devhost to
// devcoordinator as a reply to RunCompatibilityTests, when llcpp can support
// making an asynchronous fidl call.
CompleteCompatibilityTests(CompatibilityTestStatus status);
const uint32 FRAGMENT_NAME_MAX = 32;
struct Fragment {
string:FRAGMENT_NAME_MAX name;
LocalDeviceId id;
/// Protocol for controlling a devhost process from the devcoordinator
protocol DevhostController {
/// Create a device in the devhost that only implements the device protocol
/// and claims to support the given `protocol_id`. This device will communicate
/// with the devcoordinator via `coordinator`. Implements DeviceController on device_controller_rpc
CreateDeviceStub(Coordinator coordinator_rpc, request<DeviceController> device_controller_rpc, uint32 protocol_id, LocalDeviceId local_device_id);
/// Create a device in the devhost representing the shadowed half of device
/// in another devhost. This new device will communicate with the devcoordinator
/// via `rpc`, and with its other half via `parent_proxy`.
/// The new device will have the given driver responsible for running its half
/// of the driver's cross-process protocol. It's create() method will be invoked,
/// giving it access to `parent_proxy` and `proxy_args`.
/// parent_proxy, if present, will usually be a channel to the upper half of
/// a shadowed device. The one exception is when this method is used
/// to create the Platform Bus, in which case it will be a channel to a
/// fuchsia.boot.Items protocol.
/// `local_device_id` will be a unique value within the device's devhost
CreateDevice(Coordinator coordinator_rpc, request<DeviceController> device_controller_rpc, string:DEVICE_PATH_MAX driver_path,
zx.handle:VMO driver, handle? parent_proxy,
string:DEVICE_ARGS_MAX? proxy_args, LocalDeviceId local_device_id);
/// Introduce a composite device that has the given name and properties.
/// `fragments` will be a list of all of the composite's fragments,
/// described using devhost local device ids. The order of the fragments
/// will match the original composite creation request. The new device will
/// communicate with devcoordinator via `rpc`.
/// `local_device_id` will be a unique value within the device's devhost, identifying
/// the resulting composite device.
CreateCompositeDevice(Coordinator coordinator_rpc, request<DeviceController> device_controller_rpc,
vector<Fragment>:FRAGMENTS_MAX fragments,
string:DEVICE_NAME_MAX name, LocalDeviceId local_device_id)
-> (zx.status status);
/// Interface for the devices in devhosts to coordinate with the devcoordinator.
protocol Coordinator {
/// Record the addition of a new device that can be communicated with via `rpc`.
/// For binding purposes, it is has properties `props`. `name` and `driver_path`
/// are informational and used for debugging. The device will have `protocol_id`
/// as its primary protocol id. `args` should only be used for shadowed devices,
/// and will be forwarded to the shadow device. `client_remote`, if present,
/// will be passed to the device as an open connection for the client.
/// On success, the returned `local_device_id` is the identifier assigned by devmgr.
AddDevice(request<Coordinator> coordinator, DeviceController device_controller,
vector<DeviceProperty>:PROPERTIES_MAX props,
string:DEVICE_NAME_MAX name, uint32 protocol_id,
string:DEVICE_PATH_MAX? driver_path, string:DEVICE_ARGS_MAX? args,
AddDeviceConfig device_add_config, bool has_init, zx.handle:VMO? inspect,
zx.handle:CHANNEL? client_remote)
-> (LocalDeviceId local_device_id) error zx.status;
/// Requests the devcoordinator schedule the removal of this device,
/// and the unbinding of its children.
/// If `unbind_self` is true, the unbind hook for this device will also be called.
ScheduleRemove(bool unbind_self);
/// Requests the devcoordinator schedule the unbinding of this device's children.
/// Mark this device as visible.
MakeVisible() -> () error zx.status;
/// Attempt to bind a driver against this device. If `driver_path` is null,
/// this will initiate the driver matching algorithm.
// TODO(teisenbe): Specify the behavior of invoking this multiple times. I believe
// the current behavior is a bug.
BindDevice(string:DEVICE_PATH_MAX? driver_path) -> () error zx.status;
/// Returns the topological path of this device.
GetTopologicalPath() -> (string:DEVICE_PATH_MAX path) error zx.status;
/// Requests that the firmware at the given path be loaded and returned.
LoadFirmware(string:DEVICE_PATH_MAX fw_path)
-> (zx.handle:VMO vmo, uint64 size) error zx.status;
/// Retrieve the metadata blob associated with this device and the given key.
GetMetadata(uint32 key)
-> (vector<uint8>:METADATA_BYTES_MAX data) error zx.status;
/// Retrieve the metadata size associated with this device and the given key.
GetMetadataSize(uint32 key)
-> (uint64 size) error zx.status;
/// Add metadata blob associated with this device and the given key.
// TODO(teisenbe): Document the behavior of calling this twice with the same
// key. I believe the current behavior results in inaccessible data that is
// kept around for the lifetime of the device.
AddMetadata(uint32 key, vector<uint8>:METADATA_BYTES_MAX? data)
-> () error zx.status;
/// Behaves like AddMetadata, but instead of associating it with the
/// requesting device, associates it with the device at `device_path`. If
/// the device at `device_path` is not a child of the requesting device AND
/// the requesting device is not running in the sys devhost, then this will
/// fail.
PublishMetadata(string:DEVICE_PATH_MAX device_path, uint32 key,
vector<uint8>:METADATA_BYTES_MAX? data) -> () error zx.status;
/// Adds the given composite device. This causes the devcoordinator to try to match the
/// fragments against the existing device tree, and to monitor all new device additions
/// in order to find the fragments as they are created.
AddCompositeDevice(string:DEVICE_NAME_MAX name, CompositeDeviceDescriptor comp_desc)
-> () error zx.status;
/// Watches a directory, receiving events of added messages on the
/// watcher request channel.
/// See for more information.
DirectoryWatch(uint32 mask, uint32 options, zx.handle:CHANNEL watcher)
-> () error zx.status;
/// Run Compatibility tests for the driver that binds to this device.
/// The hook_wait_time is the time that the driver expects to take for
/// each device hook in nanoseconds.
/// Returns whether the compatibility tests started, and does not convey
/// anything about the status of the test.
RunCompatibilityTests(int64 hook_wait_time) -> () error zx.status;
/// Protocol for getting the information needed to debug bind programs from the devcoordinator.
protocol BindDebugger {
/// Returns the bind program of the given driver.
/// ZX_ERR_NOT_FOUND indicates that there is no driver matching the given path.
/// ZX_ERR_BUFFER_TOO_SMALL indicates that the driver's bind program is longer than the
/// maximum number of instructions (BIND_PROGRAM_INSTRUCTIONS_MAX).
GetBindProgram(string:DEVICE_PATH_MAX driver_path)
-> (vector<BindInstruction>:BIND_PROGRAM_INSTRUCTIONS_MAX instructions)
error zx.status;
/// Returns the list of properties of the given device.
/// ZX_ERR_NOT_FOUND indicates that there is no device matching the given path.
/// ZX_ERR_BAD_PATH indicates that the given path is not valid.
/// ZX_ERR_BUFFER_TOO_SMALL indicates either that the given path is too long,
/// or that the device has more than the maximum number of properties (PROPERTIES_MAX).
GetDeviceProperties(string:DEVICE_PATH_MAX device_path)
-> (vector<DeviceProperty>:PROPERTIES_MAX props) error zx.status;