From b20667b35b3effbc937914eba73761f43cc7520d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 27 Apr 2005 01:08:35 +0000 Subject: [PATCH] {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 --- headers/os/drivers/KernelExport.h | 17 ++- headers/private/kernel/arch/int.h | 13 +- headers/private/kernel/arch/ppc/arch_int.h | 12 ++ headers/private/kernel/arch/x86/arch_int.h | 13 ++ headers/private/kernel/int.h | 8 +- src/system/kernel/arch/x86/arch_cpu.c | 15 +- src/system/kernel/arch/x86/arch_int.c | 131 +++++++++++++----- src/system/kernel/arch/x86/arch_smp.c | 22 +-- src/system/kernel/arch/x86/arch_timer.c | 32 +++-- src/system/kernel/arch/x86/arch_vm.c | 1 - .../system}/kernel/arch/x86/interrupts.h | 24 +++- src/system/kernel/int.c | 111 ++++++--------- 12 files changed, 239 insertions(+), 160 deletions(-) create mode 100644 headers/private/kernel/arch/ppc/arch_int.h create mode 100644 headers/private/kernel/arch/x86/arch_int.h rename {headers/private => src/system}/kernel/arch/x86/interrupts.h (57%) diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index 2d9cd6e33f..0f6f1ecaab 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -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); diff --git a/headers/private/kernel/arch/int.h b/headers/private/kernel/arch/int.h index ed37e907c4..854f215604 100644 --- a/headers/private/kernel/arch/int.h +++ b/headers/private/kernel/arch/int.h @@ -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, 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_INT_H #define KERNEL_ARCH_INT_H #include +#include #ifdef __cplusplus diff --git a/headers/private/kernel/arch/ppc/arch_int.h b/headers/private/kernel/arch/ppc/arch_int.h new file mode 100644 index 0000000000..f98813cb07 --- /dev/null +++ b/headers/private/kernel/arch/ppc/arch_int.h @@ -0,0 +1,12 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. 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 */ diff --git a/headers/private/kernel/arch/x86/arch_int.h b/headers/private/kernel/arch/x86/arch_int.h new file mode 100644 index 0000000000..a4d613ea97 --- /dev/null +++ b/headers/private/kernel/arch/x86/arch_int.h @@ -0,0 +1,13 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. 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 */ diff --git a/headers/private/kernel/int.h b/headers/private/kernel/int.h index cdc007dcf7..42f2afa670 100644 --- a/headers/private/kernel/int.h +++ b/headers/private/kernel/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) diff --git a/src/system/kernel/arch/x86/arch_cpu.c b/src/system/kernel/arch/x86/arch_cpu.c index 688ceb54da..b8b9343682 100644 --- a/src/system/kernel/arch/x86/arch_cpu.c +++ b/src/system/kernel/arch/x86/arch_cpu.c @@ -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, 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. + */ #include #include #include #include -#include #include #include +#include "interrupts.h" + #include #include #include diff --git a/src/system/kernel/arch/x86/arch_int.c b/src/system/kernel/arch/x86/arch_int.c index c4f5367901..a4c574e7e6 100644 --- a/src/system/kernel/arch/x86/arch_int.c +++ b/src/system/kernel/arch/x86/arch_int.c @@ -20,12 +20,49 @@ #include #include -#include #include #include +#include "interrupts.h" + #include + +//#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); diff --git a/src/system/kernel/arch/x86/arch_smp.c b/src/system/kernel/arch/x86/arch_smp.c index 95ff995e04..e6a30d01f7 100644 --- a/src/system/kernel/arch/x86/arch_smp.c +++ b/src/system/kernel/arch/x86/arch_smp.c @@ -1,10 +1,11 @@ /* -** Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. 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, 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. + */ + #include #include @@ -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; } diff --git a/src/system/kernel/arch/x86/arch_timer.c b/src/system/kernel/arch/x86/arch_timer.c index e289e7770f..4ba13f4e9f 100644 --- a/src/system/kernel/arch/x86/arch_timer.c +++ b/src/system/kernel/arch/x86/arch_timer.c @@ -1,7 +1,11 @@ -/* -** Copyright 2001, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. 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 #include @@ -16,23 +20,25 @@ #include -#include #include #include -#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(); diff --git a/src/system/kernel/arch/x86/arch_vm.c b/src/system/kernel/arch/x86/arch_vm.c index 0c7b4fece6..8dd77d16b3 100644 --- a/src/system/kernel/arch/x86/arch_vm.c +++ b/src/system/kernel/arch/x86/arch_vm.c @@ -16,7 +16,6 @@ #include #include -#include #include diff --git a/headers/private/kernel/arch/x86/interrupts.h b/src/system/kernel/arch/x86/interrupts.h similarity index 57% rename from headers/private/kernel/arch/x86/interrupts.h rename to src/system/kernel/arch/x86/interrupts.h index dcf0d262e7..3ed47aa0c1 100644 --- a/headers/private/kernel/arch/x86/interrupts.h +++ b/src/system/kernel/arch/x86/interrupts.h @@ -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 */ diff --git a/src/system/kernel/int.c b/src/system/kernel/int.c index 7e2ac03c33..2bfb44b00b 100644 --- a/src/system/kernel/int.c +++ b/src/system/kernel/int.c @@ -17,22 +17,29 @@ #include #include +//#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) */