2002-07-09 16:24:59 +04:00
|
|
|
/*
|
|
|
|
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
|
|
|
** Distributed under the terms of the NewOS License.
|
|
|
|
*/
|
2002-07-10 19:48:19 +04:00
|
|
|
|
2002-07-10 17:08:47 +04:00
|
|
|
#include <kernel.h>
|
|
|
|
#include <int.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <memheap.h>
|
|
|
|
#include <smp.h>
|
|
|
|
#include <arch/int.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stage2.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#define NUM_IO_VECTORS 256
|
|
|
|
|
|
|
|
struct io_handler {
|
2002-07-18 19:03:13 +04:00
|
|
|
struct io_handler *next;
|
|
|
|
int (*func)(void*);
|
|
|
|
void* data;
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct io_vector {
|
2002-07-18 19:03:13 +04:00
|
|
|
struct io_handler *handler_list;
|
|
|
|
spinlock_t vector_lock;
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct io_vector *io_vectors = NULL;
|
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
|
|
|
|
int
|
|
|
|
int_init(kernel_args *ka)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-18 19:03:13 +04:00
|
|
|
dprintf("init_int_handlers: entry\n");
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
return arch_int_init(ka);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
|
|
|
|
int
|
|
|
|
int_init2(kernel_args *ka)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-18 19:03:13 +04:00
|
|
|
io_vectors = (struct io_vector *)kmalloc(sizeof(struct io_vectors *) * NUM_IO_VECTORS);
|
|
|
|
if (io_vectors == NULL)
|
|
|
|
panic("int_init2: could not create io vector table!\n");
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
memset(io_vectors, 0, sizeof(struct io_vector *) * NUM_IO_VECTORS);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
return arch_int_init2(ka);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
|
|
|
|
int
|
|
|
|
int_set_io_interrupt_handler(int vector, int (*func)(void*), void* data)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-18 19:03:13 +04:00
|
|
|
struct io_handler *io;
|
|
|
|
int state;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
// insert this io handler in the chain of interrupt
|
|
|
|
// handlers registered for this io interrupt
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
io = (struct io_handler *)kmalloc(sizeof(struct io_handler));
|
|
|
|
if (io == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
io->func = func;
|
|
|
|
io->data = data;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
state = int_disable_interrupts();
|
|
|
|
acquire_spinlock(&io_vectors[vector].vector_lock);
|
|
|
|
io->next = io_vectors[vector].handler_list;
|
|
|
|
io_vectors[vector].handler_list = io;
|
|
|
|
release_spinlock(&io_vectors[vector].vector_lock);
|
|
|
|
int_restore_interrupts(state);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
arch_int_enable_io_interrupt(vector);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
int
|
|
|
|
int_remove_io_interrupt_handler(int vector, int (*func)(void*), void* data)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-18 19:03:13 +04:00
|
|
|
struct io_handler *io, *prev = NULL;
|
|
|
|
int state;
|
|
|
|
|
|
|
|
// lock the structures down so it is not modified while we search
|
|
|
|
state = int_disable_interrupts();
|
|
|
|
acquire_spinlock(&io_vectors[vector].vector_lock);
|
|
|
|
|
|
|
|
// start at the beginning
|
|
|
|
io = io_vectors[vector].handler_list;
|
|
|
|
|
|
|
|
// while not at end
|
|
|
|
while (io != NULL) {
|
|
|
|
// see if we match both the function & data
|
|
|
|
if (io->func == func && io->data == data)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Store our backlink and move to next
|
|
|
|
prev = io;
|
|
|
|
io = io->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we found it
|
|
|
|
if (io != NULL) {
|
|
|
|
// unlink it, taking care of the change it was the first in line
|
|
|
|
if (prev != NULL)
|
|
|
|
prev->next = io->next;
|
|
|
|
else
|
|
|
|
io_vectors[vector].handler_list = io->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// release our lock as we're done with the vector
|
|
|
|
release_spinlock(&io_vectors[vector].vector_lock);
|
|
|
|
int_restore_interrupts(state);
|
|
|
|
|
|
|
|
// and disable the IRQ if nothing left
|
|
|
|
if (io != NULL) {
|
|
|
|
if (prev == NULL && io->next == NULL)
|
|
|
|
arch_int_disable_io_interrupt(vector);
|
|
|
|
|
|
|
|
kfree(io);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (io != NULL) ? 0 : EINVAL;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-18 19:03:13 +04:00
|
|
|
int
|
|
|
|
int_io_interrupt_handler(int vector)
|
|
|
|
{
|
|
|
|
int ret = INT_NO_RESCHEDULE;
|
|
|
|
|
|
|
|
acquire_spinlock(&io_vectors[vector].vector_lock);
|
|
|
|
|
|
|
|
if (io_vectors[vector].handler_list == NULL) {
|
|
|
|
dprintf("unhandled io interrupt %d\n", vector);
|
|
|
|
} else {
|
|
|
|
struct io_handler *io;
|
|
|
|
int temp_ret;
|
|
|
|
|
|
|
|
io = io_vectors[vector].handler_list;
|
|
|
|
while (io != NULL) {
|
|
|
|
temp_ret = io->func(io->data);
|
|
|
|
if (temp_ret == INT_RESCHEDULE)
|
|
|
|
ret = INT_RESCHEDULE;
|
|
|
|
io = io->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
release_spinlock(&io_vectors[vector].vector_lock);
|
|
|
|
|
|
|
|
return ret;
|
2002-07-10 19:48:19 +04:00
|
|
|
}
|
|
|
|
|