starina_api/interrupt.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
//! A hardware interrupt object.
use core::fmt;
use starina_types::error::FtlError;
use starina_types::interrupt::Irq;
use crate::handle::OwnedHandle;
use crate::syscall;
/// A hardware interrupt object.
///
/// This object provides functionalities to handle hardware interrupts from devices
/// in device drivers:
///
/// - Enable interrupts by acquiring the object ([`Interrupt::create`]).
/// - Acknowledge the interrupt ([`Interrupt::acknowledge`]).
/// - Wait for interrupts in an event loop ([`Mainloop::add_interrupt`](crate::mainloop::Mainloop::add_interrupt))
///
/// # Example
///
/// ```
/// use starina_api::interrupt::Interrupt;
/// use starina_api::types::interrupt::Irq;
///
/// // Ideally, you should get the IRQ from the device tree.
/// let irq = Irq::new(1);
///
/// // Acquire the ownership of the interrupt.
/// let interrupt = Interrupt::create(irq).unwrap();
///
/// // Register the interrupt to the mainloop.
/// let mut mainloop = Mainloop::new().unwrap();
/// mainloop
/// .add_interrupt(interrupt, Context::Interrupt)
/// .unwrap();
///
/// // Wait for interrupts in the mainloop...
/// loop {
/// match mainloop.next() {
/// Event::Interrupt { ctx: Context::Interrupt, .. } => {
/// // Handle the interrupt.
/// do_something();
///
/// // Tell the kernel that we have handled the interrupt and are
/// // ready for the next one.
/// interrupt.acknowledge().unwrap();
/// }
/// ev => {
/// warn!("unexpected event: {:?}", ev);
/// }
/// }
/// }
/// ```
pub struct Interrupt {
handle: OwnedHandle,
}
impl Interrupt {
/// Creates a new interrupt object for the given IRQ.
pub fn create(irq: Irq) -> Result<Interrupt, FtlError> {
let handle = syscall::interrupt_create(irq)?;
let interrupt = Interrupt {
handle: OwnedHandle::from_raw(handle),
};
Ok(interrupt)
}
/// Instantiates the object from the given handle.
pub fn from_handle(handle: OwnedHandle) -> Interrupt {
Interrupt { handle }
}
/// Returns the handle.
pub fn handle(&self) -> &OwnedHandle {
&self.handle
}
/// Acknowledges the interrupt.
///
/// This tells the CPU (or the interrupt controller) that the interrupt has
/// been handled and we are ready to receive the next one.
pub fn acknowledge(&self) -> Result<(), FtlError> {
syscall::interrupt_ack(self.handle().id())
}
}
impl fmt::Debug for Interrupt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Interrupt({:?})", self.handle)
}
}