70 lines
1.6 KiB
C
70 lines
1.6 KiB
C
#include <zinnia/assert.h>
|
|
#include <zinnia/irq.h>
|
|
#include <zinnia/list.h>
|
|
#include <zinnia/percpu.h>
|
|
#include <zinnia/print.h>
|
|
#include <arch/irq.h>
|
|
|
|
[[__percpu]]
|
|
struct irq_percpu irq_data;
|
|
|
|
bool irq_set_state(bool state) {
|
|
return arch_irq_set_state(state);
|
|
}
|
|
|
|
bool irq_get_state() {
|
|
return arch_irq_get_state();
|
|
}
|
|
|
|
void irq_wait() {
|
|
arch_irq_wait();
|
|
}
|
|
|
|
void irq_lock() {
|
|
bool prev = arch_irq_set_state(false);
|
|
struct irq_percpu* state = percpu_ref(irq_data);
|
|
if (state->depth++ == 0)
|
|
state->saved_state = prev;
|
|
}
|
|
|
|
void irq_unlock() {
|
|
struct irq_percpu* state = percpu_ref(irq_data);
|
|
if (--state->depth == 0 && state->saved_state)
|
|
arch_irq_set_state(true);
|
|
}
|
|
|
|
void irq_line_program(struct irq_line* line, enum irq_trigger_mode trigger, enum irq_polarity polarity) {
|
|
irq_lock();
|
|
line->mode = line->set_config(line, trigger, polarity);
|
|
irq_unlock();
|
|
}
|
|
|
|
void irq_line_raise(struct irq_line* line) {
|
|
assert(!arch_irq_get_state(), "Raised an IRQ line with interrupts enabled");
|
|
|
|
irq_lock();
|
|
line->is_busy = true;
|
|
|
|
bool claimed = false;
|
|
struct irq_handler* handler;
|
|
list_foreach(handler, &line->handlers, next) {
|
|
if (handler->raise(handler) == IRQ_STATUS_HANDLED)
|
|
claimed = true;
|
|
}
|
|
|
|
if (!claimed)
|
|
log("irq: Spurious interrupt\n");
|
|
|
|
if ((line->mode & IRQ_MODE_EOI) && line->eoi)
|
|
line->eoi(line);
|
|
|
|
line->is_busy = false;
|
|
irq_unlock();
|
|
}
|
|
|
|
void irq_line_attach(struct irq_line* line, struct irq_handler* handler) {
|
|
irq_lock();
|
|
list_insert_head(&line->handlers, handler, next);
|
|
irq_unlock();
|
|
}
|