blob: fc58006b130eb9158ca6ee815a1ae41e1e85f023 [file] [log] [blame]
// Copyright 2019 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 zx;
@transport("Syscall")
closed protocol Interrupt {
/// ## Summary
///
/// Create an interrupt object.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_interrupt_create(zx_handle_t src_obj,
/// uint32_t src_num,
/// uint32_t options,
/// zx_handle_t* out_handle);
/// ```
///
/// ## Description
///
/// `zx_interrupt_create()` creates an interrupt object that represents a physical
/// or virtual interrupt.
///
/// If *options* is `ZX_INTERRUPT_VIRTUAL`, *src_obj* and *src_num* are ignored and
/// a virtual interrupt is returned.
///
/// Otherwise *src_obj* must be a suitable resource for creating platform interrupts
/// or a PCI object, and *src_num* is the associated interrupt number. This restricts
/// the creation of interrupts to the internals of the DDK (driver development kit).
/// Physical interrupts are obtained by drivers through various DDK APIs.
///
/// Physical interrupts honor the options `ZX_INTERRUPT_EDGE_LOW`, `ZX_INTERRUPT_EDGE_HIGH`,
/// `ZX_INTERRUPT_LEVEL_LOW`, `ZX_INTERRUPT_LEVEL_HIGH`, and `ZX_INTERRUPT_REMAP_IRQ`.
///
/// The handles will have `ZX_RIGHT_INSPECT`, `ZX_RIGHT_DUPLICATE`, `ZX_RIGHT_TRANSFER`
/// (allowing them to be sent to another process via [`zx_channel_write()`]), `ZX_RIGHT_READ`,
/// `ZX_RIGHT_WRITE` (required for [`zx_interrupt_ack()`]), `ZX_RIGHT_WAIT` (required for
/// [`zx_interrupt_wait()`], and `ZX_RIGHT_SIGNAL` (required for [`zx_interrupt_trigger()`]).
///
/// Interrupts are said to be "triggered" when the underlying physical interrupt occurs
/// or when [`zx_interrupt_trigger()`] is called on a virtual interrupt. A triggered interrupt,
/// when bound to a port with [`zx_interrupt_bind()`], causes a packet to be delivered to the port.
///
/// If not bound to a port, an interrupt object may be waited on with [`zx_interrupt_wait()`].
///
/// Interrupts cannot be waited on with the `zx_object_wait_` family of calls.
///
/// ## Rights
///
/// *src_obj* must have resource kind `ZX_RSRC_KIND_IRQ`.
///
/// ## Return value
///
/// `zx_interrupt_create()` returns `ZX_OK` on success. In the event
/// of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` the *src_obj* handle is invalid (if this is not a virtual interrupt)
///
/// `ZX_ERR_WRONG_TYPE` the *src_obj* handle is not of an appropriate type to create an interrupt.
///
/// `ZX_ERR_ACCESS_DENIED` the *src_obj* handle does not allow this operation.
///
/// `ZX_ERR_INVALID_ARGS` *options* contains invalid flags or the *out_handle*
/// parameter is an invalid pointer.
///
/// `ZX_ERR_NO_MEMORY` Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_interrupt_ack()`]
/// - [`zx_interrupt_bind()`]
/// - [`zx_interrupt_destroy()`]
/// - [`zx_interrupt_wait()`]
/// - [`zx_port_wait()`]
///
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_interrupt_ack()`]: interrupt_ack.md
/// [`zx_interrupt_bind()`]: interrupt_bind.md
/// [`zx_interrupt_destroy()`]: interrupt_destroy.md
/// [`zx_interrupt_trigger()`]: interrupt_trigger.md
/// [`zx_interrupt_wait()`]: interrupt_wait.md
/// [`zx_port_wait()`]: port_wait.md
strict Create(resource struct {
src_obj Handle:RESOURCE;
src_num uint32;
options uint32;
}) -> (resource struct {
out_handle Handle:INTERRUPT;
}) error Status;
/// ## Summary
///
/// Bind an interrupt object to a port.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_interrupt_bind(zx_handle_t handle,
/// zx_handle_t port_handle,
/// uint64_t key,
/// uint32_t options);
/// ```
///
/// ## Description
///
/// `zx_interrupt_bind()` binds or unbinds an interrupt object to a port.
///
/// An interrupt object may only be bound to a single port and may only be bound once.
/// The interrupt can only bind to a port created with `ZX_PORT_BIND_TO_INTERRUPT`
/// option.
///
/// When a bound interrupt object is triggered, a `ZX_PKT_TYPE_INTERRUPT` packet will
/// be delivered to the port it is bound to, with the timestamp (relative to `ZX_CLOCK_MONOTONIC`)
/// of when the interrupt was triggered in the `zx_packet_interrupt_t`. The *key* used
/// when binding the interrupt will be present in the `key` field of the `zx_port_packet_t`.
///
/// If the interrupt being bound is in a triggered state, then a
/// `ZX_PKT_TYPE_INTERRUPT` packet will be sent to the port the interrupt is being bound to,
/// with the timestamp of when the interrupt was triggered. This packet will need
/// to be processed normally.
///
/// To bind to a port pass `ZX_INTERRUPT_BIND` in *options*.
///
/// To unbind a previously bound port pass `ZX_INTERRUPT_UNBIND` in *options*. For unbind the
/// *port_handle* is required but the *key* is ignored. Unbinding the port removes previously
/// queued packets to the port.
///
/// Before another packet may be delivered, the bound interrupt must be re-armed using the
/// [`zx_interrupt_ack()`] syscall. This is (in almost all cases) best done after the interrupt
/// packet has been fully processed. Especially in the case of multiple threads reading
/// packets from a port, if the processing thread re-arms the interrupt and it has triggered,
/// a packet will immediately be delivered to a waiting thread.
///
/// Interrupt packets are delivered via a dedicated queue on ports and are higher priority
/// than non-interrupt packets.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_INTERRUPT` and have `ZX_RIGHT_READ`.
///
/// *port_handle* must be of type `ZX_OBJ_TYPE_PORT` and have `ZX_RIGHT_WRITE`.
///
/// ## Return value
///
/// `zx_interrupt_bind()` returns `ZX_OK` on success. In the event
/// of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* or *port_handle* is not a valid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not an interrupt object or *port_handle* is not a port object.
///
/// `ZX_ERR_CANCELED` [`zx_interrupt_destroy()`] was called on *handle*.
///
/// `ZX_ERR_BAD_STATE` A thread is waiting on the interrupt using [`zx_interrupt_wait()`]
///
/// `ZX_ERR_ACCESS_DENIED` the *handle* handle lacks `ZX_RIGHT_READ` or the *port_handle* handle
/// lacks `ZX_RIGHT_WRITE`
///
/// `ZX_ERR_ALREADY_BOUND` this interrupt object is already bound.
///
/// `ZX_ERR_INVALID_ARGS` *options* is not `ZX_INTERRUPT_BIND` or `ZX_INTERRUPT_UNBIND`.
///
/// `ZX_ERR_NOT_FOUND` the *port* does not match the bound port.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_interrupt_ack()`]
/// - [`zx_interrupt_create()`]
/// - [`zx_interrupt_destroy()`]
/// - [`zx_interrupt_trigger()`]
/// - [`zx_interrupt_wait()`]
/// - [`zx_port_wait()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_interrupt_ack()`]: interrupt_ack.md
/// [`zx_interrupt_create()`]: interrupt_create.md
/// [`zx_interrupt_destroy()`]: interrupt_destroy.md
/// [`zx_interrupt_trigger()`]: interrupt_trigger.md
/// [`zx_interrupt_wait()`]: interrupt_wait.md
/// [`zx_port_wait()`]: port_wait.md
strict Bind(resource struct {
handle Handle:INTERRUPT;
port_handle Handle:PORT;
key uint64;
options uint32;
}) -> () error Status;
/// ## Summary
///
/// Wait for an interrupt.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_interrupt_wait(zx_handle_t handle, zx_time_t* out_timestamp);
/// ```
///
/// ## Description
///
/// `zx_interrupt_wait()` is a blocking syscall that causes the caller to
/// wait until an interrupt is triggered. It can only be used on interrupt
/// objects that have not been bound to a port with [`zx_interrupt_bind()`]
///
/// It also, before the waiting begins, will acknowledge the interrupt object,
/// as if [`zx_interrupt_ack()`] were called on it.
///
/// The wait may be aborted with [`zx_interrupt_destroy()`] or by closing the handle.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_INTERRUPT` and have `ZX_RIGHT_WAIT`.
///
/// ## Return value
///
/// `zx_interrupt_wait()` returns `ZX_OK` on success, and *out_timestamp*, if
/// non-NULL, returns the timestamp of when the interrupt was triggered (relative
/// to `ZX_CLOCK_MONOTONIC`)
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is an invalid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not a handle to an interrupt object.
///
/// `ZX_ERR_BAD_STATE` the interrupt object is bound to a port.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* lacks `ZX_RIGHT_WAIT`.
///
/// `ZX_ERR_CANCELED` *handle* was closed while waiting or [`zx_interrupt_destroy()`] was called
/// on it.
///
/// `ZX_ERR_INVALID_ARGS` the *out_timestamp* parameter is an invalid pointer.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_interrupt_ack()`]
/// - [`zx_interrupt_bind()`]
/// - [`zx_interrupt_create()`]
/// - [`zx_interrupt_destroy()`]
/// - [`zx_interrupt_trigger()`]
/// - [`zx_port_wait()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_interrupt_ack()`]: interrupt_ack.md
/// [`zx_interrupt_bind()`]: interrupt_bind.md
/// [`zx_interrupt_create()`]: interrupt_create.md
/// [`zx_interrupt_destroy()`]: interrupt_destroy.md
/// [`zx_interrupt_trigger()`]: interrupt_trigger.md
/// [`zx_port_wait()`]: port_wait.md
@blocking
strict Wait(resource struct {
handle Handle:INTERRUPT;
}) -> (struct {
out_timestamp Time;
}) error Status;
// TODO(https://fxbug.dev/42107929): No DESTROY rights here.
/// ## Summary
///
/// Destroys an interrupt object.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_interrupt_destroy(zx_handle_t handle);
/// ```
///
/// ## Description
///
/// `zx_interrupt_destroy()` "destroys" an interrupt object, putting it in a state
/// where any [`zx_interrupt_wait()`] operations on it will return `ZX_ERR_CANCELED`,
/// and it is unbound from any ports it was bound to.
///
/// This provides a clean shut down mechanism. Closing the last handle to the
/// interrupt object results in similar cancellation but could result in use-after-close
/// of the handle.
///
/// If the interrupt object is bound to a port when cancellation happens, if it
/// has not yet triggered, or it has triggered but the packet has not yet been
/// received by a caller of [`zx_port_wait()`], success is returned and any packets
/// in flight are removed. Otherwise, `ZX_ERR_NOT_FOUND` is returned, indicating
/// that the packet has been read but the interrupt has not been re-armed by calling
/// [`zx_interrupt_ack()`].
///
/// ## Rights
///
/// TODO(https://fxbug.dev/42107318)
///
/// ## Return value
///
/// `zx_interrupt_destroy()` returns `ZX_OK` on success. In the event
/// of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is an invalid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not an interrupt object.
///
/// `ZX_ERR_NOT_FOUND` *handle* was bound (and now no longer is) but was not
/// being waited for.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* lacks `ZX_RIGHT_WRITE`.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_interrupt_ack()`]
/// - [`zx_interrupt_bind()`]
/// - [`zx_interrupt_create()`]
/// - [`zx_interrupt_trigger()`]
/// - [`zx_interrupt_wait()`]
/// - [`zx_port_wait()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_interrupt_ack()`]: interrupt_ack.md
/// [`zx_interrupt_bind()`]: interrupt_bind.md
/// [`zx_interrupt_create()`]: interrupt_create.md
/// [`zx_interrupt_trigger()`]: interrupt_trigger.md
/// [`zx_interrupt_wait()`]: interrupt_wait.md
/// [`zx_port_wait()`]: port_wait.md
strict Destroy(resource struct {
handle Handle:INTERRUPT;
}) -> () error Status;
/// ## Summary
///
/// Acknowledge an interrupt and re-arm it.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_interrupt_ack(zx_handle_t handle);
/// ```
///
/// ## Description
///
/// `zx_interrupt_ack()` acknowledges an interrupt object, causing it to be eligible
/// to trigger again (and delivering a packet to the port it is bound to).
///
/// If the interrupt object is a physical interrupt, if it is a level interrupt and
/// still asserted, or is an edge interrupt that has been asserted since it last
/// triggered, the interrupt will trigger immediately, delivering a packet to the
/// port it is bound to.
///
/// Virtual interrupts behave as edge interrupts.
///
/// This syscall only operates on interrupts bound to a port. Interrupts
/// being waited upon with [`zx_interrupt_wait()`] do not need to be re-armed with this
/// call -- it happens automatically when [`zx_interrupt_wait()`] is called.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_INTERRUPT` and have `ZX_RIGHT_WRITE`.
///
/// ## Return value
///
/// `zx_interrupt_ack()` returns `ZX_OK` on success. In the event
/// of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is an invalid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not an interrupt object.
///
/// `ZX_ERR_BAD_STATE` *handle* is not bound to a port.
///
/// `ZX_ERR_CANCELED` [`zx_interrupt_destroy()`] was called on *handle*.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* lacks `ZX_RIGHT_WRITE`.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_interrupt_bind()`]
/// - [`zx_interrupt_create()`]
/// - [`zx_interrupt_destroy()`]
/// - [`zx_interrupt_trigger()`]
/// - [`zx_interrupt_wait()`]
/// - [`zx_port_wait()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_interrupt_bind()`]: interrupt_bind.md
/// [`zx_interrupt_create()`]: interrupt_create.md
/// [`zx_interrupt_destroy()`]: interrupt_destroy.md
/// [`zx_interrupt_trigger()`]: interrupt_trigger.md
/// [`zx_interrupt_wait()`]: interrupt_wait.md
/// [`zx_port_wait()`]: port_wait.md
strict Ack(resource struct {
handle Handle:INTERRUPT;
}) -> () error Status;
/// ## Summary
///
/// Triggers a virtual interrupt object.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_interrupt_trigger(zx_handle_t handle,
/// uint32_t options,
/// zx_time_t timestamp);
/// ```
///
/// ## Description
///
/// `zx_interrupt_trigger()` is used to trigger a virtual interrupt interrupt object,
/// causing an interrupt message packet to arrive on the bound port, if it is bound
/// to a port, or [`zx_interrupt_wait()`] to return if it is waiting on this interrupt.
///
/// *options* must be zero.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_INTERRUPT` and have `ZX_RIGHT_SIGNAL`.
///
/// ## Return value
///
/// `zx_interrupt_trigger()` returns `ZX_OK` on success. In the event
/// of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is an invalid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not an interrupt object.
///
/// `ZX_ERR_BAD_STATE` *handle* is not a virtual interrupt.
///
/// `ZX_ERR_CANCELED` [`zx_interrupt_destroy()`] was called on *handle*.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* lacks `ZX_RIGHT_SIGNAL`.
///
/// `ZX_ERR_INVALID_ARGS` *options* is non-zero.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_interrupt_ack()`]
/// - [`zx_interrupt_bind()`]
/// - [`zx_interrupt_create()`]
/// - [`zx_interrupt_destroy()`]
/// - [`zx_interrupt_wait()`]
/// - [`zx_port_wait()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_interrupt_ack()`]: interrupt_ack.md
/// [`zx_interrupt_bind()`]: interrupt_bind.md
/// [`zx_interrupt_create()`]: interrupt_create.md
/// [`zx_interrupt_destroy()`]: interrupt_destroy.md
/// [`zx_interrupt_wait()`]: interrupt_wait.md
/// [`zx_port_wait()`]: port_wait.md
strict Trigger(resource struct {
handle Handle:INTERRUPT;
options uint32;
timestamp Time;
}) -> () error Status;
};