blob: 4bac4b669aa1febf0acd2ca80c3db00961bb468d [file] [log] [blame] [edit]
// Copyright 2024 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.
@available(added=HEAD)
library fuchsia.hardware.hrtimer;
using zx;
using fuchsia.power.system;
/// Maximum count of timers supported by this protocol, arbitrary.
const MAX_COUNT_TIMERS uint32 = 64;
/// Maximum count of resolutions supported by a given timer, arbitrary.
const MAX_COUNT_RESOLUTIONS uint32 = 64;
/// Errors that this driver may return.
type DriverError = flexible enum {
/// The driver encountered an otherwise unspecified error while performing the operation.
INTERNAL_ERROR = 1;
/// The operation is not implemented, supported, or enabled.
NOT_SUPPORTED = 2;
/// An argument is invalid.
INVALID_ARGS = 3;
/// The operation failed because the current state of the driver does not allow it, or a
/// precondition of the operation is not satisfied.
BAD_STATE = 4;
/// The in-progress operation has been canceled.
CANCELED = 5;
};
/// Amount of time for one tick of a timer.
type Resolution = flexible union {
/// The resolution specified for one tick.
1: duration zx.Duration;
};
/// Properties for a specific timer abstracted by the driver.
type TimerProperties = table {
/// Unique identifier for this timer.
///
/// The `id` is stable for a given timer, i.e. it does not change across different clients
/// or different connections from the same client.
///
/// Required.
1: id uint64;
/// Retrieves the resolutions supported by this timer.
///
/// Required.
2: supported_resolutions vector<Resolution>:MAX_COUNT_RESOLUTIONS;
/// Range in ticks.
///
/// This is the maximum amount of time that can be set in terms of ticks when a timer is
/// started. The maximum range in actual time (e.g. nanoseconds) depends on the resolution used.
///
/// NOTE: The value reported here does not need to be identical to what
/// the hardware actually supports. The driver MAY provide the support for
/// the reported `max_ticks` that is greater than the largest value of ticks
/// that can be put into the device's hardware register. The driver supports
/// a greater value of `max_ticks` by re-programming the hardware counter multiple times
/// with its maximum supported interval, with an interrupt generated after
/// each re-programming. If you want as few re-programmings (and interrupts)
/// to happen as possible, as may be the case when using the hrtimer in a power-aware
/// context, select the coarsest available resolution from [supported_resolutions].
/// This will ensure the longest possible wall-clock time passes without a re-program.
///
/// Required.
3: max_ticks uint64;
// Someday we should re-evaluate the use of these bools to tell the user
// what method(s) are supported. They already do that by returning
// kNotSupported.
/// If true then the `SetEvent` method is supported, if false or not present it is not
/// supported.
///
/// Optional.
4: supports_event bool;
/// If true then the `StartAndWait` and `StartAndWait2` methods are supported, if false or
/// not present these methods are not supported.
///
/// Optional.
5: supports_wait bool;
/// If true, then the `TimerRead` and `ClockRead` methods are supported, if
/// false or not present, these methods are not supported.
///
/// Optional.
6: supports_read bool;
};
/// Driver properties.
type Properties = resource table {
/// Retrieves the supported timers properties.
///
/// Optional.
1: timers_properties vector<TimerProperties>:MAX_COUNT_TIMERS;
};
/// A driver providing high resolution timers support.
/// This API is intended for timers that are provided by hardware separate from the CPU
/// For instance this driver may abstract hardware provided by an SoC.
@discoverable
open protocol Device {
/// Start the timer `id` to expire after `ticks`.
///
/// If `ticks` is 0 then the timer will expire in 0 ticks (immediately).
/// If the timer `id` was already started, then the previous `Start` is canceled and the driver
/// will restart the timer. Note that this may race with the expiration of the previous timer,
/// for instance the notification process may be already started and a new `Start` call won't
/// be able to stop a notification that is already in flight.
/// If the specified `id` is invalid, then this call will return `INVALID_ARGS`.
/// If the specified `resolution` is not supported per the `resolutions` provided by
/// `GetProperties`, then this call will return `INVALID_ARGS`.
/// If the specified `ticks` is beyond the range supported for the timer as provided by
/// `GetProperties`, then this call will return `INVALID_ARGS`.
/// If the driver encounters an internal error, then this call will return `INTERNAL_ERROR`.
flexible Start(struct {
id uint64;
resolution Resolution;
ticks uint64;
}) -> () error DriverError;
/// Read the current timer's set or timeout value.
///
/// The returned ticks are in time-units relative to the given resolution.
/// Use `GetProperties()` to determine the available resolution(s).
///
/// Errors:
/// BAD_STATE: no readable timer currently exists.
/// INVALID_ARGS: `id` or `resolution` are invalid or unsupported values.
/// NOT_SUPPORTED: if `supports_read` is false, or the method is otherwise
/// not implemented.
/// INTERNAL_ERROR: internal runtime error.
flexible ReadTimer(struct {
id uint64;
resolution Resolution;
}) -> (struct {
ticks uint64;
}) error DriverError;
/// Read the current timer's clock value.
///
/// The returned ticks are in time-units relative to the given resolution.
/// Use `GetProperties()` to determine the available resolution(s).
///
/// Errors:
/// BAD_STATE: no clock is currently running.
/// INVALID_ARGS: `id` or `resolution` are invalid or unsupported values.
/// NOT_SUPPORTED: if `supports_read` is false, or the method is otherwise
/// not implemented.
/// INTERNAL_ERROR: internal runtime error.
flexible ReadClock(struct {
id uint64;
resolution Resolution;
}) -> (struct {
ticks uint64;
}) error DriverError;
/// Stops the timer `id`.
///
/// Note that this may race with the expiration of the timer, for instance notification via
/// an event set with `SetEvent` may be already in flight.
/// If the specified `id` is invalid, then this call will return `INVALID_ARGS`.
/// If the driver encounters an internal error, then this call will return `INTERNAL_ERROR`.
flexible Stop(struct {
id uint64;
}) -> () error DriverError;
/// Get the current time in ticks left in timer `id` until expiration.
///
/// If the specified `id` is invalid, then this call will return `INVALID_ARGS`.
flexible GetTicksLeft(struct {
id uint64;
}) -> (struct {
ticks uint64;
}) error DriverError;
/// Sets a Zircon Event to be notified of the timer expiration.
///
/// The timer expiration will be notified via the ZX_EVENT_SIGNALED signal.
/// The client is responsible for clearing the ZX_EVENT_SIGNALED signal.
/// Any previously event set for the specific `id` is replaced. Note that this may race with
/// the event signaling from the expiration of a timer already started.
/// To guarantee that an event is delivered upon timer expiration, this method must be
/// called before calling `Start`.
///
/// If the specified `id` is invalid, then this call will return `INVALID_ARGS`.
/// If this method is not supported for the given `id`, then this call will return
/// `NOT_SUPPORTED`.
/// If the driver encounters an internal error, then this call will return `INTERNAL_ERROR`.
flexible SetEvent(resource struct {
id uint64;
event zx.Handle:EVENT;
}) -> () error DriverError;
/// Start the timer `id` to expire after `ticks` and waits until the timer expires with
/// support for preventing suspension via the Power Framework.
///
/// The driver will signal the `setup_event` event once the timer has been setup using the
/// ZX_EVENT_SIGNALED signal. This allows a client to know that it is safe to allow the
/// system to suspend. The client is responsible for clearing this event.
///
/// The driver will not respond to this call (hang) until the timer has triggered.
/// Calling `Stop` on the timer will abort this call and return `CANCELED`. Note that this
/// may race with the expiration of the timer.
///
/// A driver supporting this call must be able to get a lease on a power element that keeps
/// the system from suspending. This lease is returned to the client via the `keep_alive`
/// LeaseToken channel field. When `keep_alive` is closed, then the driver lease keeping the
/// system from suspending will be dropped. Hence, to guarantee that the system is not
/// suspended by the Power Framework a client must either keep this `keep_alive` token for
/// as long as the system needs to not suspend, or a client must get its own lease from the
/// Power Framework to prevent suspension before it drops `keep_alive`.
///
/// If the specified `id` is invalid, then this call will return `INVALID_ARGS`.
/// If this method is not supported for the given `id`, then this call will return
/// `NOT_SUPPORTED`.
/// If the driver does not have a `keep_alive` token to provide to the client, then this
/// call will return `BAD_STATE`.
/// If the driver encounters an internal error, then this call will return `INTERNAL_ERROR`.
flexible StartAndWait(resource struct {
id uint64;
resolution Resolution;
ticks uint64;
setup_event zx.Handle:EVENT;
}) -> (resource struct {
keep_alive fuchsia.power.system.LeaseToken;
}) error DriverError;
/// Start timer `id` and wait for it to expire after `ticks` ticks.
///
/// The driver will not respond to this call (hang) until the timer has triggered.
/// Calling `Stop` on the timer will abort this call and return `CANCELED`. Note that this
/// may race with the expiration of the timer.
///
/// This method keeps the system awake (prevents suspension) while the timer is setup using the
/// mandatory passed-in `setup_keep_alive` `LeaseToken`.
/// When the timer expires this method returns a second `expiration_keep_alive`
/// `LeaseToken` to prevent suspension at the time of expiration.
/// These keep alive wake lease tokens are provided by the Power Framework's System Activity
/// Governor. A driver supporting this call must be able to get `expiration_keep_alive` from
/// System Activity Governor.
///
/// When `expiration_keep_alive` is closed, then this driver created wake lease keeping the
/// system from suspending at the time of the timer expiration is dropped. Hence, to guarantee
/// that the system is not suspended by the Power Framework a client must either keep this
/// `expiration_keep_alive` for as long as the system needs to stay awake, or a client must
/// get its own wake lease from the Power Framework before it drops `expiration_keep_alive` to
/// prevent suspension.
///
/// Errors:
///
/// * INVALID_ARGS: The specified `id` is invalid.
/// * NOT_SUPPORTED: This method is not supported for the given `id`.
/// * BAD_STATE: The driver is in a bad state, for instance it does not have an
/// `expiration_keep_alive` token to provide to the client.
/// * INTERNAL_ERROR: The driver encountered an internal error.
flexible StartAndWait2(resource struct {
id uint64;
resolution Resolution;
ticks uint64;
setup_keep_alive fuchsia.power.system.LeaseToken;
}) -> (resource struct {
expiration_keep_alive fuchsia.power.system.LeaseToken;
}) error DriverError;
/// Get driver properties.
flexible GetProperties() -> (resource struct {
properties Properties;
});
};
service Service {
device client_end:Device;
};