blob: 3c63543160649442220cdfa625ef9b87afc89174 [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 components that a composite device can have
const uint32 COMPONENTS_MAX = 16;
/// Maximum number of parts that a composite device component can have
const uint32 DEVICE_COMPONENT_PARTS_MAX = 16;
/// Maximum number of instructions in the match program of a device component part
const uint32 DEVICE_COMPONENT_PART_INSTRUCTIONS_MAX = 32;
// Maximum number of instructions in a driver bind program
const uint32 BIND_PROGRAM_INSTRUCTIONS_MAX = 256;
/// Bit flags for device add configuration
bits AddDeviceConfig : uint32 {
/// Device can be a component in multiple composite devices
ALLOW_MULTI_COMPOSITE = 0x00000001;
};
/// A part of a description of a DeviceComponent
struct DeviceComponentPart {
// 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_COMPONENT_PART_INSTRUCTIONS_MAX match_program;
};
/// A piece of a composite device
struct DeviceComponent {
// 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 parts_count;
array<DeviceComponentPart>:DEVICE_COMPONENT_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<DeviceComponent>:COMPONENTS_MAX components;
uint32 coresident_device_index;
vector<DeviceMetadata>:METADATA_MAX? metadata;
};
/// A enum of CompatibilityTestStatus
enum CompatibilityTestStatus : uint32 {
OK = 1;
ERR_BIND_NO_DDKADD = 2;
ERR_BIND_TIMEOUT = 3;
ERR_UNBIND_NO_DDKREMOVE = 4;
ERR_UNBIND_TIMEOUT = 5;
ERR_SUSPEND_DDKREMOVE = 6;
ERR_INTERNAL = 7;
};
/// 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, handle<vmo> driver)
-> (zx.status status, handle<channel>? test_output);
/// Give this device a channel to its shadow in another process.
ConnectProxy(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);
};
/// 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,
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.
/// `components` will be a list of all of the composite's components,
/// described using devhost local device ids. The order of the components
/// 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<LocalDeviceId>:COMPONENTS_MAX components,
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,
handle<channel>? client_remote)
-> (LocalDeviceId local_device_id) error zx.status;
/// Behaves as AddDevice, but marks the device as initially invisible. This means
/// that it will not be visible to other devices or the devfs until it is later marked
/// visible (via MakeVisible).
AddDeviceInvisible(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, bool has_init,
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.
ScheduleUnbindChildren();
/// 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)
-> (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
/// components against the existing device tree, and to monitor all new device additions
/// in order to find the components 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 fuchsia.io.Directory for more information.
DirectoryWatch(uint32 mask, uint32 options, 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.
[Discoverable]
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;
};