{install|remove}_io_interrupt_handler() now correctly handle the B_NO_ENABLE_COUNTER flag.
Lots of cleanup:
- moved B_NO_ENABLE_COUNTER flag definition out of int.h to KernelExport.h, as it's
described in the BeBook (although it's probably not really used that often :))
- int.c no longer has any platform dependent code (+ 0x20 on interrupt numbers is gone);
it's now entirely handled in the arch/x86/ section.
- the io_vectors[] is now statically initialized, instead of allocated from the heap
- removed {install|remove}_interrupt_handler(); they weren't that useful, arch_smp_init()
is now calling install_io_interrupt_handler() correctly instead
- introduced a new arch_int.h header file that currently contains NUM_IO_VECTORS only
(though on x86, it also has ARCH_INTERRUPT_BASE == 0x20).
- changed the return type from {install|remove}_io_interrupt_handler() from "long" to
"status_t"
- rearranged and cleaned the PIC initialization code, made the PIC code more prominent
- changed comments that talk about a non existing 8239 (the PIC chip is actually 8259)
- moved arch/x86/interrupts.h to the source directory, as it's not used outside
- added BeOS compatible interrupts_enabled() function, that should replace our
equivalent (and private) are_interrupts_enabled()
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12477 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
/* Kernel only exports for kernel add-ons
|
||||
**
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2005, Haiku Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_EXPORT_H
|
||||
#define _KERNEL_EXPORT_H
|
||||
|
||||
@@ -15,6 +16,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/* interrupts and spinlocks */
|
||||
|
||||
/* disable/restore interrupts on the current CPU */
|
||||
|
||||
@@ -36,16 +38,19 @@ extern void release_spinlock(spinlock *lock);
|
||||
|
||||
/* interrupt handling support for device drivers */
|
||||
|
||||
typedef int32 (*interrupt_handler)(void *data);
|
||||
|
||||
/* Values returned by interrupt handlers */
|
||||
#define B_UNHANDLED_INTERRUPT 0 /* pass to next handler */
|
||||
#define B_HANDLED_INTERRUPT 1 /* don't pass on */
|
||||
#define B_INVOKE_SCHEDULER 2 /* don't pass on; invoke the scheduler */
|
||||
|
||||
typedef int32 (*interrupt_handler)(void *data);
|
||||
/* Flags that can be passed to install_io_interrupt_handler() */
|
||||
#define B_NO_ENABLE_COUNTER 1
|
||||
|
||||
extern long install_io_interrupt_handler(long interrupt_number,
|
||||
extern status_t install_io_interrupt_handler(long interrupt_number,
|
||||
interrupt_handler handler, void *data, ulong flags);
|
||||
extern long remove_io_interrupt_handler(long interrupt_number,
|
||||
extern status_t remove_io_interrupt_handler(long interrupt_number,
|
||||
interrupt_handler handler, void *data);
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/*
|
||||
** Copyright 2002-2004, The Haiku Team. All rights reserved.
|
||||
** Distributed under the terms of the Haiku License.
|
||||
**
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
* Copyright 2002-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef KERNEL_ARCH_INT_H
|
||||
#define KERNEL_ARCH_INT_H
|
||||
|
||||
|
||||
#include <boot/kernel_args.h>
|
||||
#include <arch_int.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_PPC_INT_H
|
||||
#define _KERNEL_ARCH_PPC_INT_H
|
||||
|
||||
|
||||
#define NUM_IO_VECTORS 256
|
||||
|
||||
|
||||
#endif /* _KERNEL_ARCH_PPC_INT_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_x86_INT_H
|
||||
#define _KERNEL_ARCH_x86_INT_H
|
||||
|
||||
|
||||
#define ARCH_INTERRUPT_BASE 0x20
|
||||
#define NUM_IO_VECTORS (256 - ARCH_INTERRUPT_BASE)
|
||||
|
||||
|
||||
#endif /* _KERNEL_ARCH_x86_INT_H */
|
||||
@@ -15,10 +15,6 @@
|
||||
struct kernel_args;
|
||||
|
||||
|
||||
/* adds the handler but don't change whether or not the interrupt is currently enabled */
|
||||
#define B_NO_ENABLE_COUNTER 1
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -26,8 +22,8 @@ extern "C" {
|
||||
status_t int_init(struct kernel_args *args);
|
||||
status_t int_init_post_vm(struct kernel_args *args);
|
||||
int int_io_interrupt_handler(int vector);
|
||||
status_t install_interrupt_handler(long vector, interrupt_handler, void *data);
|
||||
status_t remove_interrupt_handler(long vector, interrupt_handler, void *data);
|
||||
|
||||
bool interrupts_enabled(void);
|
||||
|
||||
static inline void
|
||||
enable_interrupts(void)
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
** Copyright 2002-2004, The Haiku Team. All rights reserved.
|
||||
** Distributed under the terms of the Haiku License.
|
||||
**
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
* Copyright 2002-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <vm.h>
|
||||
#include <smp.h>
|
||||
#include <arch/x86/selector.h>
|
||||
#include <arch/x86/interrupts.h>
|
||||
#include <tls.h>
|
||||
#include <boot/kernel_args.h>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -20,12 +20,49 @@
|
||||
#include <arch/smp.h>
|
||||
#include <arch/user_debugger.h>
|
||||
|
||||
#include <arch/x86/interrupts.h>
|
||||
#include <arch/x86/faults.h>
|
||||
#include <arch/x86/descriptors.h>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//#define TRACE_ARCH_INT
|
||||
#ifdef TRACE_ARCH_INT
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
// Definitions for the PIC 8259 controller
|
||||
// (this is not a complete list, only what we're actually using)
|
||||
|
||||
#define PIC_MASTER_CONTROL 0x20
|
||||
#define PIC_MASTER_MASK 0x21
|
||||
#define PIC_SLAVE_CONTROL 0xa0
|
||||
#define PIC_SLAVE_MASK 0xa1
|
||||
#define PIC_MASTER_INIT1 PIC_MASTER_CONTROL
|
||||
#define PIC_MASTER_INIT2 PIC_MASTER_MASK
|
||||
#define PIC_MASTER_INIT3 PIC_MASTER_MASK
|
||||
#define PIC_MASTER_INIT4 PIC_MASTER_MASK
|
||||
#define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL
|
||||
#define PIC_SLAVE_INIT2 PIC_SLAVE_MASK
|
||||
#define PIC_SLAVE_INIT3 PIC_SLAVE_MASK
|
||||
#define PIC_SLAVE_INIT4 PIC_SLAVE_MASK
|
||||
|
||||
#define PIC_INIT1 0x10
|
||||
#define PIC_INIT1_SEND_INIT4 0x01
|
||||
#define PIC_INIT3_IR2_IS_SLAVE 0x04
|
||||
#define PIC_INIT3_SLAVE_ID2 0x02
|
||||
#define PIC_INIT4_x86_MODE 0x01
|
||||
|
||||
#define PIC_NON_SPECIFIC_EOI 0x20
|
||||
|
||||
#define PIC_INT_BASE 0x20
|
||||
#define PIC_SLAVE_INT_BASE 0x28
|
||||
#define PIC_NUM_INTS 0x0f
|
||||
|
||||
const char *kInterruptNames[] = {
|
||||
/* 0 */ "Divide Error Exception",
|
||||
/* 1 */ "Debug Exception",
|
||||
@@ -59,18 +96,6 @@ static desc_table *idt = NULL;
|
||||
struct iframe_stack gBootFrameStack;
|
||||
|
||||
|
||||
static void
|
||||
interrupt_ack(int n)
|
||||
{
|
||||
if (n >= 0x20 && n < 0x30) {
|
||||
// 8239 controlled interrupt
|
||||
if (n > 0x27)
|
||||
out8(0x20, 0xa0); // EOI to pic 2
|
||||
out8(0x20, 0x20); // EOI to pic 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
|
||||
{
|
||||
@@ -107,30 +132,77 @@ x86_set_task_gate(int32 n, int32 segment)
|
||||
}
|
||||
|
||||
|
||||
/** Sends a non-specified EOI (end of interrupt) notice to the PIC in
|
||||
* question (or both of them).
|
||||
* This clears the PIC interrupt in-service bit.
|
||||
*/
|
||||
|
||||
static void
|
||||
pic_end_of_interrupt(int num)
|
||||
{
|
||||
if (num >= PIC_INT_BASE && num <= PIC_INT_BASE + PIC_NUM_INTS) {
|
||||
// PIC 8259 controlled interrupt
|
||||
if (num >= PIC_SLAVE_INT_BASE)
|
||||
out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL);
|
||||
|
||||
// we always need to acknowledge the master PIC
|
||||
out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pic_init(void)
|
||||
{
|
||||
// Start initialization sequence for the master and slave PICs
|
||||
out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1);
|
||||
out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1);
|
||||
|
||||
// Set start of interrupts to 0x20 for master, 0x28 for slave
|
||||
out8(PIC_INT_BASE, PIC_MASTER_INIT2);
|
||||
out8(PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2);
|
||||
|
||||
// Specify cascading through interrupt 2
|
||||
out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3);
|
||||
out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3);
|
||||
|
||||
// Set both to operate in 8086 mode
|
||||
out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4);
|
||||
out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4);
|
||||
|
||||
out8(0xfb, PIC_MASTER_MASK); // Mask off all interrupts (except slave pic line IRQ 2).
|
||||
out8(0xff, PIC_SLAVE_MASK); // Mask off interrupts on the slave.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_enable_io_interrupt(int irq)
|
||||
{
|
||||
if (irq < 0 || irq >= 0x10)
|
||||
// interrupt is specified "normalized"
|
||||
if (irq < 0 || irq > PIC_NUM_INTS)
|
||||
return;
|
||||
|
||||
//dprintf("arch_int_enable_io_interrupt: irq %d\n", irq);
|
||||
// enable PIC 8259 controlled interrupt
|
||||
|
||||
TRACE(("arch_int_enable_io_interrupt: irq %d\n", irq));
|
||||
|
||||
/* if this is a external interrupt via 8239, enable it here */
|
||||
if (irq < 8)
|
||||
out8(in8(0x21) & ~(1 << irq), 0x21);
|
||||
out8(in8(PIC_MASTER_MASK) & ~(1 << irq), PIC_MASTER_MASK);
|
||||
else
|
||||
out8(in8(0xa1) & ~(1 << (irq - 8)), 0xa1);
|
||||
out8(in8(PIC_SLAVE_MASK) & ~(1 << (irq - 8)), PIC_SLAVE_MASK);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_disable_io_interrupt(int irq)
|
||||
{
|
||||
/* never disable slave pic line IRQ 2 */
|
||||
if (irq < 0 || irq >= 0x10 || irq == 2)
|
||||
// interrupt is specified "normalized"
|
||||
// never disable slave pic line IRQ 2
|
||||
if (irq < 0 || irq > PIC_NUM_INTS || irq == 2)
|
||||
return;
|
||||
|
||||
/* if this is a external interrupt via 8239, disable it here */
|
||||
// disable PIC 8259 controlled interrupt
|
||||
|
||||
if (irq < 8)
|
||||
out8(in8(0x21) | (1 << irq), 0x21);
|
||||
else
|
||||
@@ -282,9 +354,9 @@ i386_handle_trap(struct iframe frame)
|
||||
}
|
||||
|
||||
default:
|
||||
if (frame.vector >= 0x20) {
|
||||
interrupt_ack(frame.vector); // ack the 8239 (if applicable)
|
||||
ret = int_io_interrupt_handler(frame.vector);
|
||||
if (frame.vector >= ARCH_INTERRUPT_BASE) {
|
||||
pic_end_of_interrupt(frame.vector);
|
||||
ret = int_io_interrupt_handler(frame.vector - ARCH_INTERRUPT_BASE);
|
||||
} else {
|
||||
panic("i386_handle_trap: unhandled trap 0x%x (%s) at ip 0x%x, thread 0x%x!\n",
|
||||
frame.vector, kInterruptNames[frame.vector], frame.eip, thread ? thread->id : -1);
|
||||
@@ -324,16 +396,7 @@ arch_int_init(kernel_args *args)
|
||||
idt = (desc_table *)args->arch_args.vir_idt;
|
||||
|
||||
// setup the interrupt controller
|
||||
out8(0x11, 0x20); // Start initialization sequence for #1.
|
||||
out8(0x11, 0xa0); // ...and #2.
|
||||
out8(0x20, 0x21); // Set start of interrupts for #1 (0x20).
|
||||
out8(0x28, 0xa1); // Set start of interrupts for #2 (0x28).
|
||||
out8(0x04, 0x21); // Set #1 to be the master.
|
||||
out8(0x02, 0xa1); // Set #2 to be the slave.
|
||||
out8(0x01, 0x21); // Set both to operate in 8086 mode.
|
||||
out8(0x01, 0xa1);
|
||||
out8(0xfb, 0x21); // Mask off all interrupts (except slave pic line IRQ 2).
|
||||
out8(0xff, 0xa1); // Mask off interrupts on the slave.
|
||||
pic_init();
|
||||
|
||||
set_intr_gate(0, &trap0);
|
||||
set_intr_gate(1, &trap1);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
** Copyright 2002-2004, Axel Dörfler, [email protected]. All rights reserved.
|
||||
** Distributed under the terms of the Haiku License.
|
||||
**
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
* Copyright 2002-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <boot/kernel_args.h>
|
||||
#include <vm.h>
|
||||
@@ -120,10 +121,11 @@ arch_smp_init(kernel_args *args)
|
||||
// set up the local apic on the boot cpu
|
||||
arch_smp_per_cpu_init(args, 0);
|
||||
|
||||
install_interrupt_handler(0xfb, &i386_timer_interrupt, NULL);
|
||||
install_interrupt_handler(0xfd, &i386_ici_interrupt, NULL);
|
||||
install_interrupt_handler(0xfe, &i386_smp_error_interrupt, NULL);
|
||||
install_interrupt_handler(0xff, &i386_spurious_interrupt, NULL);
|
||||
// I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted
|
||||
install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &i386_timer_interrupt, NULL, 0);
|
||||
install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, 0);
|
||||
install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, 0);
|
||||
install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, 0);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/*
|
||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <boot/stage2.h>
|
||||
#include <kernel.h>
|
||||
@@ -16,23 +20,25 @@
|
||||
|
||||
#include <arch/timer.h>
|
||||
|
||||
#include <arch/x86/interrupts.h>
|
||||
#include <arch/x86/smp_priv.h>
|
||||
#include <arch/x86/timer.h>
|
||||
|
||||
#define pit_clock_rate 1193180
|
||||
#define pit_max_timer_interval ((long long)0xffff * 1000000 / pit_clock_rate)
|
||||
#include "interrupts.h"
|
||||
|
||||
|
||||
#define PIT_CLOCK_RATE 1193180
|
||||
#define PIT_MAX_TIMER_INTERVAL ((long long)0xffff * 1000000 / PIT_CLOCK_RATE)
|
||||
|
||||
|
||||
static void
|
||||
set_isa_hardware_timer(long long relative_timeout)
|
||||
{
|
||||
unsigned short next_event_clocks;
|
||||
uint16 next_event_clocks;
|
||||
|
||||
if (relative_timeout <= 0)
|
||||
next_event_clocks = 2;
|
||||
else if (relative_timeout < pit_max_timer_interval)
|
||||
next_event_clocks = relative_timeout * pit_clock_rate / 1000000;
|
||||
else if (relative_timeout < PIT_MAX_TIMER_INTERVAL)
|
||||
next_event_clocks = relative_timeout * PIT_CLOCK_RATE / 1000000;
|
||||
else
|
||||
next_event_clocks = 0xffff;
|
||||
|
||||
@@ -84,10 +90,10 @@ arch_timer_clear_hardware_timer(void)
|
||||
|
||||
|
||||
int
|
||||
arch_init_timer(kernel_args *ka)
|
||||
arch_init_timer(kernel_args *args)
|
||||
{
|
||||
dprintf("arch_init_timer: entry\n");
|
||||
|
||||
//dprintf("arch_init_timer: entry\n");
|
||||
|
||||
install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0);
|
||||
clear_isa_hardware_timer();
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <arch/int.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include <arch/x86/interrupts.h>
|
||||
#include <arch/x86/bios.h>
|
||||
|
||||
|
||||
|
||||
+18
-6
@@ -1,9 +1,17 @@
|
||||
/*
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef _NEWOS_KERNEL_ARCH_I386_INTERRUPTS_H
|
||||
#define _NEWOS_KERNEL_ARCH_I386_INTERRUPTS_H
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_x86_INTERRUPTS_H
|
||||
#define _KERNEL_ARCH_x86_INTERRUPTS_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void trap0();void trap1();void trap2();void trap3();void trap4();void trap5();
|
||||
void trap6();void trap7();void trap9();void trap10();void trap11();
|
||||
@@ -17,5 +25,9 @@ void double_fault(); // int 8
|
||||
void trap99();
|
||||
|
||||
void trap251();void trap252();void trap253();void trap254();void trap255();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _KERNEL_ARCH_x86_INTERRUPTS_H */
|
||||
+40
-71
@@ -17,22 +17,29 @@
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
//#define TRACE_INT
|
||||
#ifdef TRACE_INT
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
#define NUM_IO_VECTORS 256
|
||||
|
||||
struct io_handler {
|
||||
struct io_handler *next;
|
||||
struct io_handler *prev;
|
||||
interrupt_handler func;
|
||||
void *data;
|
||||
bool use_enable_counter;
|
||||
};
|
||||
|
||||
struct io_vector {
|
||||
struct io_handler handler_list;
|
||||
spinlock vector_lock;
|
||||
int32 enable_count;
|
||||
};
|
||||
|
||||
static struct io_vector *io_vectors = NULL;
|
||||
static struct io_vector io_vectors[NUM_IO_VECTORS];
|
||||
|
||||
|
||||
cpu_status
|
||||
@@ -49,6 +56,13 @@ restore_interrupts(cpu_status status)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
interrupts_enabled(void)
|
||||
{
|
||||
return arch_int_are_interrupts_enabled();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
int_init(kernel_args *args)
|
||||
{
|
||||
@@ -63,13 +77,10 @@ int_init_post_vm(kernel_args *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
io_vectors = (struct io_vector *)malloc(sizeof(struct io_vector) * NUM_IO_VECTORS);
|
||||
if (io_vectors == NULL)
|
||||
panic("int_init_post_vm: could not create io vector table!\n");
|
||||
|
||||
/* initialize the vector list */
|
||||
for (i = 0; i < NUM_IO_VECTORS; i++) {
|
||||
io_vectors[i].vector_lock = 0; /* initialize spinlock */
|
||||
io_vectors[i].enable_count = 0;
|
||||
initque(&io_vectors[i].handler_list); /* initialize handler queue */
|
||||
}
|
||||
|
||||
@@ -77,14 +88,12 @@ int_init_post_vm(kernel_args *args)
|
||||
}
|
||||
|
||||
|
||||
/** This function is used internally to install a handler on the given vector.
|
||||
* NB this does NOT take an IRQ, but a system interrupt value.
|
||||
* As this is intended for system use this function does NOT call
|
||||
* arch_int_enable_io_interrupt() as it only works for IRQ values
|
||||
/** Install a handler to be called when an interrupt is triggered
|
||||
* for the given interrupt number with \a data as the argument.
|
||||
*/
|
||||
|
||||
status_t
|
||||
install_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, ulong flags)
|
||||
{
|
||||
struct io_handler *io = NULL;
|
||||
cpu_status state;
|
||||
@@ -92,25 +101,28 @@ install_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
if (vector < 0 || vector >= NUM_IO_VECTORS)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
/* find the chain of handlers for this irq.
|
||||
* NB there can be multiple handlers for the same IRQ, especially for
|
||||
* PCI drivers. Where we have multiple handlers we will call each in turn
|
||||
* until one returns a value other than B_UNHANDLED_INTERRUPT.
|
||||
*/
|
||||
io = (struct io_handler *)malloc(sizeof(struct io_handler));
|
||||
if (io == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
io->func = handler;
|
||||
io->data = data;
|
||||
io->use_enable_counter = (flags & B_NO_ENABLE_COUNTER) == 0;
|
||||
|
||||
/* Disable the interrupts, get the spinlock for this irq only
|
||||
* and then insert the handler */
|
||||
// Disable the interrupts, get the spinlock for this irq only
|
||||
// and then insert the handler
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&io_vectors[vector].vector_lock);
|
||||
|
||||
insque(io, &io_vectors[vector].handler_list);
|
||||
|
||||
// If B_NO_ENABLE_COUNTER is set, we're being asked to not alter
|
||||
// whether the interrupt should be enabled or not
|
||||
if (io->use_enable_counter) {
|
||||
if (io_vectors[vector].enable_count++ == 0)
|
||||
arch_int_enable_io_interrupt(vector);
|
||||
}
|
||||
|
||||
release_spinlock(&io_vectors[vector].vector_lock);
|
||||
restore_interrupts(state);
|
||||
|
||||
@@ -118,41 +130,14 @@ install_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
}
|
||||
|
||||
|
||||
/** install a handler to be called when an interrupt is triggered
|
||||
* for the given irq with data as the argument
|
||||
*/
|
||||
|
||||
long
|
||||
install_io_interrupt_handler(long irq, interrupt_handler handler, void *data, ulong flags)
|
||||
{
|
||||
// ToDo: this is x86 specific
|
||||
long vector = irq + 0x20;
|
||||
|
||||
status_t status = install_interrupt_handler(vector, handler, data);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
/* If we were passed the bit-flag B_NO_ENABLE_COUNTER then
|
||||
* we're being asked to not alter whether the interrupt is set
|
||||
* regardless of setting.
|
||||
*/
|
||||
if ((flags & B_NO_ENABLE_COUNTER) == 0)
|
||||
arch_int_enable_io_interrupt(irq);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Removes and interrupt handler.
|
||||
* Read the notes for install_interrupt_handler!
|
||||
*/
|
||||
/** Remove a previously installed interrupt handler */
|
||||
|
||||
status_t
|
||||
remove_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
{
|
||||
struct io_handler *io = NULL;
|
||||
status_t status = B_BAD_VALUE;
|
||||
int state;
|
||||
struct io_handler *io = NULL;
|
||||
cpu_status state;
|
||||
|
||||
if (vector < 0 || vector >= NUM_IO_VECTORS)
|
||||
return B_BAD_VALUE;
|
||||
@@ -171,18 +156,20 @@ remove_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
/* we have to match both function and data */
|
||||
if (io->func == handler && io->data == data) {
|
||||
remque(io);
|
||||
|
||||
// Check if we need to disable the interrupt
|
||||
if (io->use_enable_counter && --io_vectors[vector].enable_count == 0)
|
||||
arch_int_disable_io_interrupt(vector);
|
||||
|
||||
status = B_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* to finish we need to release our locks and return
|
||||
* the value rv
|
||||
*/
|
||||
release_spinlock(&io_vectors[vector].vector_lock);
|
||||
restore_interrupts(state);
|
||||
|
||||
/* if the handler could be found and removed, we still have to free it */
|
||||
// if the handler could be found and removed, we still have to free it
|
||||
if (status == B_OK)
|
||||
free(io);
|
||||
|
||||
@@ -190,24 +177,6 @@ remove_interrupt_handler(long vector, interrupt_handler handler, void *data)
|
||||
}
|
||||
|
||||
|
||||
/** remove an interrupt handler previously inserted */
|
||||
|
||||
long
|
||||
remove_io_interrupt_handler(long irq, interrupt_handler handler, void *data)
|
||||
{
|
||||
long vector = irq + 0x20;
|
||||
status_t status = remove_interrupt_handler(vector, handler, data);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
/* Check if we need to disable interrupts... */
|
||||
if (io_vectors[vector].handler_list.next != &io_vectors[vector].handler_list)
|
||||
arch_int_disable_io_interrupt(irq);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** actually process an interrupt via the handlers registered for that
|
||||
* vector (irq)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user