summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2009-05-18 17:45:21 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2009-05-18 17:45:21 +0000
commitecf2e42310bae0c04902368add58024782c88a9c (patch)
tree3c2de10e4e3f1d082be7b999bb26cd1ed8ac44d9
parent2009-05-18 Joel Sherrill <joel.sherrill@OARcorp.com> (diff)
downloadrtems-ecf2e42310bae0c04902368add58024782c88a9c.tar.bz2
2009-05-18 Joel Sherrill <joel.sherrill@OARcorp.com>
* shared/irq/irq.c, shared/irq/irq.h, shared/irq/irq_asm.S: Add shared interrupt support to i386.
-rw-r--r--c/src/lib/libbsp/i386/ChangeLog5
-rw-r--r--c/src/lib/libbsp/i386/shared/irq/irq.c193
-rw-r--r--c/src/lib/libbsp/i386/shared/irq/irq.h3
-rw-r--r--c/src/lib/libbsp/i386/shared/irq/irq_asm.S6
4 files changed, 165 insertions, 42 deletions
diff --git a/c/src/lib/libbsp/i386/ChangeLog b/c/src/lib/libbsp/i386/ChangeLog
index dd4190cf97..a0a02e8407 100644
--- a/c/src/lib/libbsp/i386/ChangeLog
+++ b/c/src/lib/libbsp/i386/ChangeLog
@@ -1,3 +1,8 @@
+2009-05-18 Joel Sherrill <joel.sherrill@OARcorp.com>
+
+ * shared/irq/irq.c, shared/irq/irq.h, shared/irq/irq_asm.S: Add shared
+ interrupt support to i386.
+
2009-03-12 Joel Sherrill <joel.sherrill@OARcorp.com>
PR 1385/cpukit
diff --git a/c/src/lib/libbsp/i386/shared/irq/irq.c b/c/src/lib/libbsp/i386/shared/irq/irq.c
index 73a3284d7b..e61bfe9a7f 100644
--- a/c/src/lib/libbsp/i386/shared/irq/irq.c
+++ b/c/src/lib/libbsp/i386/shared/irq/irq.c
@@ -2,7 +2,7 @@
*
* This file contains the implementation of the function described in irq.h
*
- * CopyRight (C) 1998 valette@crf.canon.fr
+ * Copyright (C) 1998 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
@@ -195,7 +195,63 @@ static int isValidInterrupt(int irq)
}
/*
- * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
+ * ------------------- RTEMS Shared Irq Handler Mngt Routines ------------
+ */
+int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq)
+{
+ rtems_interrupt_level level;
+ rtems_irq_connect_data* vchain;
+
+ if (!isValidInterrupt(irq->name)) {
+ printk("Invalid interrupt vector %d\n",irq->name);
+ return 0;
+ }
+
+ rtems_interrupt_disable(level);
+
+ if ( (int)rtems_hdl_tbl[irq->name].next_handler == -1 ) {
+ rtems_interrupt_enable(level);
+ printk(
+ "IRQ vector %d already connected to an unshared handler\n",
+ irq->name
+ );
+ return 0;
+ }
+
+ vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
+
+ /* save off topmost handler */
+ vchain[0]= rtems_hdl_tbl[irq->name];
+
+ /*
+ * store the data provided by user
+ */
+ rtems_hdl_tbl[irq->name] = *irq;
+
+ /* link chain to new topmost handler */
+ rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
+
+ /*
+ * enable_irq_at_pic is supposed to ignore
+ * requests to disable interrupts outside
+ * of the range handled by the PIC
+ */
+ BSP_irq_enable_at_i8259s (irq->name);
+
+ /*
+ * Enable interrupt on device
+ */
+ if (irq->on)
+ irq->on(irq);
+
+ rtems_interrupt_enable(level);
+
+ return 1;
+}
+
+
+/*
+ * --------------- RTEMS Single Irq Handler Mngt Routines ---------------
*/
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
@@ -222,6 +278,8 @@ int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
* store the data provided by user
*/
rtems_hdl_tbl[irq->name] = *irq;
+ rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
+
/*
* Enable interrupt at PIC level
*/
@@ -229,7 +287,7 @@ int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
/*
* Enable interrupt on device
*/
- if (irq->on)
+ if (irq->on)
irq->on(irq);
rtems_interrupt_enable(level);
@@ -252,43 +310,86 @@ int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq)
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
{
- rtems_interrupt_level level;
+ rtems_interrupt_level level;
+ rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
- if (!isValidInterrupt(irq->name)) {
+ if (!isValidInterrupt(irq->name)) {
+ return 0;
+ }
+
+ /*
+ * Check if default handler is actually connected. If not issue an error.
+ * You must first get the current handler via i386_get_current_idt_entry
+ * and then disconnect it using i386_delete_idt_entry.
+ * RATIONALE : to always have the same transition by forcing the user
+ * to get the previous handler before accepting to disconnect.
+ */
+ rtems_interrupt_disable(level);
+ if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
+ rtems_interrupt_enable(level);
+ return 0;
+ }
+
+ if ( (int)rtems_hdl_tbl[irq->name].next_handler != -1 ) {
+ int found = 0;
+
+ for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
+ (vchain->hdl != default_rtems_entry.hdl);
+ (pchain= vchain,
+ vchain = (rtems_irq_connect_data*)vchain->next_handler) ) {
+ if ( vchain->hdl == irq->hdl ) {
+ found = -1;
+ break;
+ }
+ }
+
+ if ( !found ) {
+ rtems_interrupt_enable(level);
return 0;
}
- /*
- * Check if default handler is actually connected. If not issue an error.
- * You must first get the current handler via i386_get_current_idt_entry
- * and then disconnect it using i386_delete_idt_entry.
- * RATIONALE : to always have the same transition by forcing the user
- * to get the previous handler before accepting to disconnect.
- */
- rtems_interrupt_disable(level);
+ } else {
if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
rtems_interrupt_enable(level);
return 0;
}
+ }
- /*
- * disable interrupt at PIC level
- */
- BSP_irq_disable_at_i8259s (irq->name);
+ /*
+ * disable interrupt at PIC level
+ */
+ BSP_irq_disable_at_i8259s (irq->name);
- /*
- * Disable interrupt on device
- */
- if (irq->off)
- irq->off(irq);
+ /*
+ * Disable interrupt on device
+ */
+ if (irq->off)
+ irq->off(irq);
- /*
- * restore the default irq value
- */
- rtems_hdl_tbl[irq->name] = default_rtems_entry;
+ /*
+ * restore the default irq value
+ */
+ if( !vchain ) {
+ /* single handler vector... */
+ rtems_hdl_tbl[irq->name] = default_rtems_entry;
+ } else {
+ if ( pchain ) {
+ /* non-first handler being removed */
+ pchain->next_handler = vchain->next_handler;
+ } else {
+ /* first handler isn't malloc'ed, so just overwrite it. Since
+ * the contents of vchain are being struct copied, vchain itself
+ * goes away
+ */
+ vchain = vchain->next_handler;
+ rtems_hdl_tbl[irq->name]= *vchain;
+ }
+ free(vchain);
+ }
- rtems_interrupt_enable(level);
- return 1;
+ rtems_interrupt_enable(level);
+
+ return 1;
}
/*
@@ -298,6 +399,7 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
{
int i;
+ rtems_irq_connect_data* vchain;
rtems_interrupt_level level;
/*
@@ -314,17 +416,16 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
compute_i8259_masks_from_prio ();
for (i=0; i < internal_config->irqNb; i++) {
- if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
+ BSP_irq_disable_at_i8259s (i);
+ for( vchain = &rtems_hdl_tbl[i];
+ ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
+ vchain = (rtems_irq_connect_data*)vchain->next_handler ) {
BSP_irq_enable_at_i8259s (i);
- if (rtems_hdl_tbl[i].on)
- rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
- }
- else {
- if (rtems_hdl_tbl[i].off)
- rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
- BSP_irq_disable_at_i8259s (i);
+ if (vchain->on)
+ vchain->on(vchain);
}
}
+
/*
* must enable slave pic anyway
*/
@@ -363,3 +464,23 @@ void processIrq(unsigned index)
rtems_hdl_tbl[index].hdl(rtems_hdl_tbl[index].handle);
}
+static inline void
+bsp_irq_dispatch_list(
+ rtems_irq_connect_data *tbl,
+ unsigned irq,
+ rtems_irq_hdl sentinel
+)
+{
+ rtems_irq_connect_data* vchain;
+ for( vchain = &tbl[irq];
+ ((int)vchain != -1 && vchain->hdl != sentinel);
+ vchain = (rtems_irq_connect_data*)vchain->next_handler ) {
+ vchain->hdl(vchain->handle);
+ }
+}
+
+
+void C_dispatch_isr(int irq)
+{
+ bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl);
+}
diff --git a/c/src/lib/libbsp/i386/shared/irq/irq.h b/c/src/lib/libbsp/i386/shared/irq/irq.h
index 77a44b9091..ce5b626a27 100644
--- a/c/src/lib/libbsp/i386/shared/irq/irq.h
+++ b/c/src/lib/libbsp/i386/shared/irq/irq.h
@@ -31,6 +31,7 @@ extern "C" {
#include <bsp/irq_asm.h>
#include <rtems.h>
+#define BSP_SHARED_HANDLER_SUPPORT 1
#include <rtems/irq.h>
/*-------------------------------------------------------------------------+
@@ -46,7 +47,7 @@ extern "C" {
* Interrupt offset in comparison to BSP_ASM_IRQ_VECTOR_BASE
* NB : 1) Interrupt vector number in IDT = offset + BSP_ASM_IRQ_VECTOR_BASE
* 2) The same name should be defined on all architecture
- * so that handler connexion can be unchanged.
+ * so that handler connection can be unchanged.
*/
#define BSP_PERIODIC_TIMER 0
#define BSP_KEYBOARD 1
diff --git a/c/src/lib/libbsp/i386/shared/irq/irq_asm.S b/c/src/lib/libbsp/i386/shared/irq/irq_asm.S
index 8c74007fbf..c8f3df3b5e 100644
--- a/c/src/lib/libbsp/i386/shared/irq/irq_asm.S
+++ b/c/src/lib/libbsp/i386/shared/irq/irq_asm.S
@@ -107,11 +107,7 @@ nested:
*/
pushl ecx /* push vector number */
- lea (ecx,ecx,2), eax
- mov SYM (rtems_hdl_tbl), edx
- shl $0x3,eax
- pushl 0x8(edx,eax,1) /* push hdl argument */
- call *0x4(edx,eax,1) /* call hdl */
+ call C_dispatch_isr
addl $4, esp
/*