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)
    }
}