| // 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 fuchsia.driver.framework as fdf; |
| using fuchsia.io; |
| using fuchsia.device; |
| using zx; |
| |
| /// This has the same structure as zx_device_prop_t. |
| type DeviceProperty = struct { |
| id uint16; |
| reserved uint16; |
| value uint32; |
| }; |
| |
| type PropertyValue = strict union { |
| 1: int_value uint32; |
| 2: str_value string:STR_LENGTH_MAX; |
| 3: bool_value bool; |
| 4: enum_value string:STR_LENGTH_MAX; |
| }; |
| |
| type DeviceStrProperty = struct { |
| key string:STR_LENGTH_MAX; |
| value PropertyValue; |
| }; |
| |
| type DevicePropertyList = struct { |
| props vector<DeviceProperty>:PROPERTIES_MAX; |
| str_props vector<DeviceStrProperty>:STR_PROPERTIES_MAX; |
| }; |
| |
| // TODO(bwb): Make this descriptive of binding, not zx_bind_inst_t |
| // currently a magic bitfield defined in binding.h |
| type BindInstruction = struct { |
| /// bitfield that encodes the operation and execution conditions |
| op uint32; |
| /// bitfield that encodes the arguments |
| arg uint32; |
| /// bitfield that encodes debugging information |
| debug uint32; |
| }; |
| |
| // Identifier used to let the devcoordinator describe specific devices during |
| // composite construction |
| alias LocalDeviceId = uint64; |
| |
| /// This definition must match `ZX_DEVICE_NAME_MAX` and is checked by a static assert. |
| const DEVICE_NAME_MAX uint32 = 31; |
| |
| /// Maximum number of bytes in a path |
| // The simple name PATH_MAX collides with a musl #define on c++ bindings. |
| const DEVICE_PATH_MAX uint32 = 1024; |
| |
| /// Maximum number of bytes in a device arguments string. |
| const DEVICE_ARGS_MAX uint32 = 1024; |
| |
| /// Maximum number of bytes in a metadata payload |
| const METADATA_BYTES_MAX uint32 = 8192; |
| |
| /// Maximum number of metadata that can be added to a device |
| const METADATA_MAX uint32 = 32; |
| |
| /// Maximum number of properties that can be attached to a device |
| const PROPERTIES_MAX uint32 = 256; |
| |
| /// Maximum number of string properties that can be attached to a device |
| const STR_PROPERTIES_MAX uint32 = 256; |
| |
| /// Maximum length of a string property key and value. |
| const STR_LENGTH_MAX uint32 = 255; |
| |
| /// Maximum number of fragments that a composite device can have |
| const FRAGMENTS_MAX uint32 = 16; |
| |
| /// Maximum number of parts that a composite device fragment can have |
| const DEVICE_FRAGMENT_PARTS_MAX uint32 = 16; |
| |
| /// Maximum number of instructions in the match program of a device fragment part |
| const DEVICE_FRAGMENT_PART_INSTRUCTIONS_MAX uint32 = 32; |
| |
| // Maximum number of instructions in a driver bind program |
| const BIND_RULES_INSTRUCTIONS_MAX uint32 = 256; |
| |
| /// Maximum length of a dispatcher scheduler role. |
| const MAX_SCHEDULER_ROLE_LENGTH uint32 = 2048; |
| |
| /// Bit flags for device add configuration |
| type AddDeviceConfig = strict bits : uint32 { |
| /// Device can be a fragment in multiple composite devices |
| ALLOW_MULTI_COMPOSITE = 0x00000001; |
| /// Device should not trigger the auto-bind mechanism |
| SKIP_AUTOBIND = 0x00000004; |
| /// Device should run in an isolated driver host from its children. |
| MUST_ISOLATE = 0x00000008; |
| }; |
| |
| /// A part of a description of a DeviceFragment |
| type DeviceFragmentPart = struct { |
| match_program vector<BindInstruction>:DEVICE_FRAGMENT_PART_INSTRUCTIONS_MAX; |
| }; |
| |
| /// A piece of a composite device |
| type DeviceFragment = struct { |
| name string:32; |
| parts vector<DeviceFragmentPart>:DEVICE_FRAGMENT_PARTS_MAX; |
| }; |
| |
| /// Metadata that can be added to a device |
| type DeviceMetadata = struct { |
| key uint32; |
| data vector<uint8>:METADATA_BYTES_MAX; |
| }; |
| |
| /// Composite device parts and properties |
| type CompositeDeviceDescriptor = struct { |
| props vector<DeviceProperty>:PROPERTIES_MAX; |
| str_props vector<DeviceStrProperty>:STR_PROPERTIES_MAX; |
| fragments vector<DeviceFragment>:FRAGMENTS_MAX; |
| primary_fragment_index uint32; |
| spawn_colocated bool; |
| metadata vector<DeviceMetadata>:<METADATA_MAX, optional>; |
| }; |
| |
| /// Composite node specification parts and properties. |
| type CompositeNodeSpecDescriptor = struct { |
| parents vector<fdf.ParentSpec>:MAX; |
| metadata vector<DeviceMetadata>:<METADATA_MAX, optional>; |
| }; |
| |
| /// Protocol for controlling devices in a devhost process from the devcoordinator |
| closed protocol DeviceController { |
| /// Connect to the device's FIDL, but also include other FIDLs multiplexed on the same channel. |
| /// |
| /// + request `include_node` if this is true then include fuchsia.io/Node on the channel. |
| /// + request `include_controller` if this is true then include fuchsia.device/Controller on the channel. |
| strict ConnectMultiplexed(resource struct { |
| server zx.Handle:CHANNEL; |
| include_node bool; |
| include_controller bool; |
| }); |
| |
| /// Connect to the device's fuchsia.device/Controller API. |
| strict ConnectToController(resource struct { |
| controller server_end:fuchsia.device.Controller; |
| }); |
| |
| /// Connect to the device's API. |
| /// |
| /// NOTE: This is not multiplexed with fuchsia.io/Node or fuchsia.device/Controller. |
| strict ConnectToDeviceProtocol(resource struct { |
| server zx.Handle:CHANNEL; |
| }); |
| |
| /// 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. |
| /// |
| /// + request `default_dispatcher_scheduler_role` the scheduler role to set for |
| /// the default dispatcher created for the driver. The scheduler role determines |
| /// the thread pool that the dispatcher will be serviced by. This may be an empty |
| /// string if the driver does not require the dispatcher to run in a specific |
| /// thread pool. Setting a scheduler role is on a best-effort basis. If an invalid |
| /// scheduler role is specified, the dispatcher will be serviced by the default |
| /// thread pool, and this will not cause an error to be returned. |
| strict BindDriver(resource struct { |
| driver_path string:DEVICE_PATH_MAX; |
| driver zx.Handle:VMO; |
| default_dispatcher_scheduler_role string:MAX_SCHEDULER_ROLE_LENGTH; |
| }) -> (resource struct { |
| status zx.Status; |
| test_output zx.Handle:<CHANNEL, optional>; |
| }); |
| |
| /// Give this device a channel to its shadow in another process. |
| strict ConnectProxy(resource struct { |
| shadow zx.Handle:CHANNEL; |
| }); |
| |
| /// Ask devhost to call the device init hook. |
| strict Init() -> (struct { |
| status zx.Status; |
| }); |
| |
| /// Ask devhost to unbind this device. On success, the remote end of this |
| /// interface channel will close instead of returning a result. |
| strict 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`. |
| strict CompleteRemoval() -> () error zx.Status; |
| |
| /// Ask devhost to suspend this device, using the target state indicated by `flags`. |
| strict Suspend(struct { |
| flags uint32; |
| }) -> (struct { |
| status zx.Status; |
| }); |
| |
| /// Ask devhost to resume this device, using the target system state indicated by |
| /// 'target_system_state'. |
| strict Resume(struct { |
| target_system_state uint32; |
| }) -> (struct { |
| status zx.Status; |
| }); |
| |
| /// Informs the driver that it has been made visible in devfs. |
| strict SignalMadeVisible(); |
| }; |
| |
| const FRAGMENT_NAME_MAX uint32 = 32; |
| |
| type Fragment = struct { |
| name string:FRAGMENT_NAME_MAX; |
| id LocalDeviceId; |
| }; |
| |
| type StubDevice = struct { |
| protocol_id uint32; |
| }; |
| |
| type ProxyDevice = resource struct { |
| driver_path string:DEVICE_PATH_MAX; |
| driver zx.Handle:VMO; |
| parent_proxy zx.Handle:CHANNEL; |
| }; |
| |
| type FidlProxyDevice = resource struct { |
| /// If this is present this represents an incoming namespace directory that the |
| /// device can use to access FIDL protocols from its parent. |
| incoming_dir client_end:<fuchsia.io.Directory, optional>; |
| }; |
| |
| type CompositeDevice = struct { |
| fragments vector<Fragment>:FRAGMENTS_MAX; |
| name string:DEVICE_NAME_MAX; |
| }; |
| |
| type DeviceType = strict resource union { |
| /// The device has no parent to communicate with and no driver to load. |
| 1: stub StubDevice; |
| |
| /// The device acts as a proxy for its parent and talks to it via its |
| /// proxy channel. |
| 2: proxy ProxyDevice; |
| |
| /// This device is a proxy for its parent which lives in another driver host. |
| /// The parent exposes FIDL protocols in its outgoing directory, which have |
| /// been routed to this device. |
| 3: fidl_proxy FidlProxyDevice; |
| |
| /// The device is a composite device with several parents, referred to as |
| /// fragments. The device aggregates all parent devices together. The order of the |
| /// fragments will match the original composite creation request. |
| 4: composite CompositeDevice; |
| }; |
| |
| /// Protocol for controlling a driver host process from the driver manager |
| closed protocol DriverHostController { |
| /// Create a device in the driver host. |type| describes what type of device |
| /// is set up, how it communicates with its parent (if it has one). |
| /// |
| /// `local_device_id` will be a unique value within the device's devhost |
| strict CreateDevice(resource struct { |
| coordinator client_end:Coordinator; |
| device_controller server_end:DeviceController; |
| type DeviceType; |
| local_device_id LocalDeviceId; |
| }) -> (struct { |
| status zx.Status; |
| }); |
| |
| // TODO(fxbug.dev/68309): Currently unimplemented. |
| /// Request to restart the driver host. Also restarts all children devices and drivers and |
| /// rebinds them once the Driver Host has restarted. |
| strict Restart() -> (struct { |
| status zx.Status; |
| }); |
| }; |
| |
| /// This struct holds non-resource arguments for creating a new device with the |
| /// Coordinator. |
| type AddDeviceArgs = struct { |
| /// The device name, used for debugging. |
| name string:DEVICE_NAME_MAX; |
| /// The protocol id, used for binding. |
| protocol_id uint32; |
| /// The property list of the device, used for binding. |
| property_list DevicePropertyList; |
| /// The driver path, used for debugging. |
| driver_path string:<DEVICE_PATH_MAX, optional>; |
| /// This should be used only for shadowed device. This will be forwarded to |
| /// the shadowed device. |
| args string:<DEVICE_ARGS_MAX, optional>; |
| device_add_config AddDeviceConfig; |
| has_init bool; |
| /// An address pointing to the DFv2 device symbol, which contains its banjo |
| /// ops. This exists on every DFv1 device, but it is only used by a DFv2 |
| /// child. |
| dfv2_device_symbol uint64; |
| }; |
| |
| /// Interface for drivers in driver host to coordinate with the driver |
| /// manager. |
| closed protocol Coordinator { |
| /// Record the addition of a new device that can be communicated with via `device_controller`. |
| /// On success, the returned `local_device_id` is the identifier assigned by devmgr. |
| // TODO(fxb/74654): String properties are unimplemented. |
| strict AddDevice(resource struct { |
| args AddDeviceArgs; |
| coordinator server_end:Coordinator; |
| device_controller client_end:DeviceController; |
| inspect zx.Handle:<VMO, optional>; |
| outgoing_dir client_end:<fuchsia.io.Directory, optional>; |
| }) -> (struct { |
| local_device_id LocalDeviceId; |
| }) 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. |
| strict ScheduleRemove(struct { |
| unbind_self bool; |
| }); |
| |
| /// Requests the devcoordinator schedule the unbinding of this device's children. |
| /// If the device has no children, no request will be sent, and `has_children` will be false. |
| strict ScheduleUnbindChildren() -> (struct { |
| has_children bool; |
| }) error zx.Status; |
| |
| /// Attempt to bind a driver against this device. |
| /// + request `driver_url_suffix` only driver's that match this URL suffix will try to bind to |
| /// the device (e.g: "fvm.cm"). |
| /// If this is null, the API will autobind. |
| /// * error `ZX_ERR_ALREADY_BOUND` if the device is already bound. |
| /// * error `ZX_ERR_NOT_FOUND` no drivers were found. |
| strict BindDevice(struct { |
| driver_url_suffix string:<DEVICE_PATH_MAX, optional>; |
| }) -> () error zx.Status; |
| |
| /// Returns the topological path of this device. |
| strict GetTopologicalPath() -> (struct { |
| path string:DEVICE_PATH_MAX; |
| }) error zx.Status; |
| |
| /// Requests that the firmware at the given path be loaded and returned. |
| strict LoadFirmware(struct { |
| driver_path string:DEVICE_PATH_MAX; |
| fw_path string:DEVICE_PATH_MAX; |
| }) -> (resource struct { |
| vmo zx.Handle:VMO; |
| size uint64; |
| }) error zx.Status; |
| |
| /// Retrieve the metadata blob associated with this device and the given key. |
| strict GetMetadata(struct { |
| key uint32; |
| }) -> (struct { |
| data vector<uint8>:METADATA_BYTES_MAX; |
| }) error zx.Status; |
| |
| /// Retrieve the metadata size associated with this device and the given key. |
| strict GetMetadataSize(struct { |
| key uint32; |
| }) -> (struct { |
| size uint64; |
| }) error zx.Status; |
| |
| /// Add metadata blob associated with this device and the given key. |
| /// If the same key is specified multiple times, the new data will be |
| /// ignored in favor of the data from first call with the specified key. |
| // TODO(fxbug.dev/112547): Return ZX_ERR_ALREADY_EXISTS on duplicate key |
| // instead. |
| strict AddMetadata(struct { |
| key uint32; |
| data vector<uint8>:<METADATA_BYTES_MAX, optional>; |
| }) -> () error zx.Status; |
| |
| /// Adds the given composite device. This causes the driver manager 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. |
| strict AddCompositeDevice(struct { |
| name string:DEVICE_NAME_MAX; |
| comp_desc CompositeDeviceDescriptor; |
| }) -> () error zx.Status; |
| |
| /// Adds the given composite node spec. This causes the driver manager to add the spec to |
| /// the driver index, and then try to match the parents against the node topology. |
| /// All device additions will be monitored to see if they matched to the remaining |
| /// unbound nodes. |
| strict AddCompositeNodeSpec(struct { |
| name string:DEVICE_NAME_MAX; |
| spec CompositeNodeSpecDescriptor; |
| }) -> () error zx.Status; |
| |
| /// Connects the given FIDL protocol inside of a FIDL service. Connection is completed |
| /// asynchronously due to pipelining. Returning `ZX_OK` does not imply the service exists. A |
| /// two way call to the service via the retained client end of the channel pair must be issued |
| /// in order to ascertain whether the connection has been successfully established. |
| /// + |fragment_name| should be specified if the parent is a composite node. |
| /// + |service_name| should be specified if attempting to connect to a service. This will be |
| /// mandatory in the future: http://fxbug.dev/107155. |
| /// * error Reports `ZX_ERR_UNAVAILABLE` if the parent (or fragment) does not have an outgoing |
| /// directory. |
| /// * error Reports `ZX_ERR_NOT_FOUND` if |fragment_name| is not the name of a parent. |
| /// * error Reports `ZX_ERR_NOT_SUPPORTED` if |fragment_name| is specified by the device is not |
| /// a composite node |
| strict ConnectFidlProtocol(resource struct { |
| fragment_name string:<DEVICE_NAME_MAX, optional>; |
| service_name string:<STR_LENGTH_MAX, optional>; |
| protocol_name string:STR_LENGTH_MAX; |
| server zx.Handle:CHANNEL; |
| }) -> () error zx.Status; |
| }; |