diff packages/kernel/current/src/intr/intr.cxx @ 2:443894e2e912 ecos-v1_2_1-release

Block commit of eCos version 1.2.1
author jlarmour
date Tue, 11 May 1999 12:24:34 +0000
parents 3111d98ba7b3
children ece80412419a
line wrap: on
line diff
--- a/packages/kernel/current/src/intr/intr.cxx
+++ b/packages/kernel/current/src/intr/intr.cxx
@@ -1,8 +1,8 @@
 //==========================================================================
 //
-//	intr/intr.cxx
+//      intr/intr.cxx
 //
-//	Interrupt class implementations
+//      Interrupt class implementations
 //
 //==========================================================================
 //####COPYRIGHTBEGIN####
@@ -22,19 +22,19 @@
 // September 30, 1998.
 // 
 // The Initial Developer of the Original Code is Cygnus.  Portions created
-// by Cygnus are Copyright (C) 1998 Cygnus Solutions.  All Rights Reserved.
+// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions.  All Rights Reserved.
 // -------------------------------------------
 //
 //####COPYRIGHTEND####
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
-// Author(s): 	nickg
-// Contributors:	nickg
-// Date:	1997-10-15
-// Purpose:	Interrupt class implementation
-// Description: This file contains the definitions of the interrupt
-//              class.
+// Author(s):    nickg
+// Contributors: nickg
+// Date:         1999-02-17
+// Purpose:      Interrupt class implementation
+// Description:  This file contains the definitions of the interrupt
+//               class.
 //
 //####DESCRIPTIONEND####
 //
@@ -54,6 +54,14 @@
 #include <cyg/kernel/sched.inl>
 
 // -------------------------------------------------------------------------
+// Statics
+
+// Interrupt disable counter. Note that this is initialized to 1 since
+// enable_interrupts() is called in Cyg_Scheduler::start().
+
+cyg_int32 Cyg_Interrupt::disable_counter = 1;
+
+// -------------------------------------------------------------------------
 
 Cyg_Interrupt::Cyg_Interrupt(
     cyg_vector      vec,                // Vector to attach to
@@ -63,6 +71,10 @@ Cyg_Interrupt::Cyg_Interrupt(
     cyg_DSR         *dr                 // Deferred Service Routine
     )
 {
+    CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG5("vector=%d, priority=%d, data=%08x, isr=%08x, "
+                        "dsr=%08x", vec, pri, d, ir, dr);
+    
     vector      = vec;
     priority    = pri;
     isr         = ir;
@@ -81,6 +93,8 @@ Cyg_Interrupt::Cyg_Interrupt(
     next        = NULL;
     
 #endif
+
+    CYG_REPORT_RETURN();
     
 };
 
@@ -88,7 +102,9 @@ Cyg_Interrupt::Cyg_Interrupt(
 
 Cyg_Interrupt::~Cyg_Interrupt()
 {
+    CYG_REPORT_FUNCTION();
     detach();
+    CYG_REPORT_RETURN();
 };
 
 // -------------------------------------------------------------------------
@@ -96,7 +112,8 @@ Cyg_Interrupt::~Cyg_Interrupt()
 
 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
 
-Cyg_Interrupt *Cyg_Interrupt::dsr_table[CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE];
+Cyg_Interrupt *
+Cyg_Interrupt::dsr_table[CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE];
 
 cyg_ucount32 Cyg_Interrupt::dsr_table_head = 0;
 
@@ -113,7 +130,8 @@ Cyg_Interrupt *Cyg_Interrupt::dsr_list =
 // -------------------------------------------------------------------------
 // Call any pending DSRs
 
-void Cyg_Interrupt::call_pending_DSRs()
+void
+Cyg_Interrupt::call_pending_DSRs_inner(void)
 {
 //    CYG_REPORT_FUNCTION();
 
@@ -159,9 +177,29 @@ void Cyg_Interrupt::call_pending_DSRs()
     
 };
 
+externC void
+cyg_interrupt_call_pending_DSRs(void)
+{
+    Cyg_Interrupt::call_pending_DSRs_inner();
+}
+
+// This function will be provided by HALs that fully implement
+// interrupt stack functionality
+externC void 
+hal_interrupt_stack_call_pending_DSRs(void)
+  __attribute__ ((weak, alias("cyg_interrupt_call_pending_DSRs")));
+
+void
+Cyg_Interrupt::call_pending_DSRs(void)
+{
+    hal_interrupt_stack_call_pending_DSRs();
+}
+
+
 // -------------------------------------------------------------------------
 
-void Cyg_Interrupt::post_dsr()
+void
+Cyg_Interrupt::post_dsr(void)
 {
 //    CYG_REPORT_FUNCTION();
 
@@ -202,8 +240,21 @@ void Cyg_Interrupt::post_dsr()
 };
 
 // -------------------------------------------------------------------------
+// A C callable interface to Cyg_Interrupt::post_dsr() that can be used from
+// the HAL.
 
-externC void interrupt_end(
+externC void
+cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj )
+{
+    Cyg_Interrupt* intr = (Cyg_Interrupt*) intr_obj;
+    intr->post_dsr ();
+}
+
+// -------------------------------------------------------------------------
+
+// FIXME: should have better name - Jifl
+externC void
+interrupt_end(
     cyg_uint32          isr_ret,
     Cyg_Interrupt       *intr,
     HAL_SavedRegisters  *regs
@@ -211,15 +262,19 @@ externC void interrupt_end(
 {
 //    CYG_REPORT_FUNCTION();
 
-    CYG_INSTRUMENT_INTR(END, intr->vector, isr_ret);
-
+    // Sometimes we have a NULL intr object pointer.
+    cyg_vector vector = (intr!=NULL)?intr->vector:0;
+    
+    CYG_INSTRUMENT_INTR(END, vector, isr_ret);
+    
+    
 #ifndef CYGIMP_KERNEL_INTERRUPTS_CHAIN
 
     // Only do this if we are in a non-chained configuration.
     // If we are chained, then chain_isr below will do the DSR
     // posting.
     
-    if( isr_ret & 2 ) intr->post_dsr();
+    if( isr_ret & Cyg_Interrupt::CALL_DSR && intr != NULL ) intr->post_dsr();
 
 #endif    
 
@@ -246,8 +301,7 @@ externC void interrupt_end(
     
 #endif    
     
-    
-    CYG_INSTRUMENT_INTR(RESTORE, intr->vector, 0);    
+    CYG_INSTRUMENT_INTR(RESTORE, vector, 0);    
 }
 
 // -------------------------------------------------------------------------
@@ -255,7 +309,7 @@ externC void interrupt_end(
 
 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
 
-Cyg_Interrupt *Cyg_Interrupt::chain_list[CYG_ISR_COUNT];
+Cyg_Interrupt *Cyg_Interrupt::chain_list[CYGNUM_HAL_ISR_COUNT];
 
 #endif
 
@@ -264,7 +318,8 @@ Cyg_Interrupt *Cyg_Interrupt::chain_list
 
 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
 
-cyg_uint32 Cyg_Interrupt::chain_isr(cyg_vector vector, CYG_ADDRWORD data)
+cyg_uint32
+Cyg_Interrupt::chain_isr(cyg_vector vector, CYG_ADDRWORD data)
 {
     Cyg_Interrupt *p = *(Cyg_Interrupt **)data;
 
@@ -276,9 +331,9 @@ cyg_uint32 Cyg_Interrupt::chain_isr(cyg_
         {
             register cyg_uint32 isr_ret = p->isr(vector, p->data);
 
-            if( isr_ret & 2 ) p->post_dsr();
+            if( isr_ret & Cyg_Interrupt::CALL_DSR ) p->post_dsr();
 
-            if( isr_ret & 1 ) break;
+            if( isr_ret & Cyg_Interrupt::HANDLED ) break;
         }
 
         p = p->next;
@@ -292,12 +347,13 @@ cyg_uint32 Cyg_Interrupt::chain_isr(cyg_
 // -------------------------------------------------------------------------
 // Attach an ISR to an interrupt vector.
 
-void Cyg_Interrupt::attach()
+void
+Cyg_Interrupt::attach(void)
 {
     CYG_REPORT_FUNCTION();
 
-    CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector");
-    CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
 
     CYG_INSTRUMENT_INTR(ATTACH, vector, 0);
 
@@ -313,11 +369,14 @@ void Cyg_Interrupt::attach()
 
     if( chain_list[index] == NULL )
     {
+        int in_use;
         // First Interrupt on this chain, just assign it and register
         // the chain_isr with the HAL.
         
         chain_list[index] = this;
 
+        HAL_INTERRUPT_IN_USE( vector, in_use );
+        CYG_ASSERT( 0 == in_use, "Interrupt vector not free.");
         HAL_INTERRUPT_ATTACH( vector, chain_isr, &chain_list[index], NULL );
     }
     else
@@ -341,20 +400,30 @@ void Cyg_Interrupt::attach()
     
 #else
     
-    HAL_INTERRUPT_ATTACH( vector, isr, data, this );
+    {
+        int in_use;
+
+
+        HAL_INTERRUPT_IN_USE( vector, in_use );
+        CYG_ASSERT( 0 == in_use, "Interrupt vector not free.");
+
+        HAL_INTERRUPT_ATTACH( vector, isr, data, this );
+    }
 
 #endif    
+    CYG_REPORT_RETURN();
 }
 
 // -------------------------------------------------------------------------
 // Detach the ISR from the vector
 
-void Cyg_Interrupt::detach()
+void
+Cyg_Interrupt::detach(void)
 {
     CYG_REPORT_FUNCTION();
 
-    CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector");    
-    CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
 
     CYG_INSTRUMENT_INTR(DETACH, vector, 0);
 
@@ -362,7 +431,11 @@ void Cyg_Interrupt::detach()
 
     // Remove the interrupt object from the vector chain.
     
-    Cyg_Interrupt **p = &chain_list[vector];
+    cyg_uint32 index;
+
+    HAL_TRANSLATE_VECTOR( vector, index );
+
+    Cyg_Interrupt **p = &chain_list[index];
 
     while( *p != NULL )
     {
@@ -379,7 +452,7 @@ void Cyg_Interrupt::detach()
 
     // If this was the last one, detach the vector.
     
-    if( chain_list[vector] == NULL )
+    if( chain_list[index] == NULL )
         HAL_INTERRUPT_DETACH( vector, chain_isr );
     
 #else
@@ -387,33 +460,44 @@ void Cyg_Interrupt::detach()
     HAL_INTERRUPT_DETACH( vector, isr );
 
 #endif
+
+    CYG_REPORT_RETURN();
     
 }
 
 // -------------------------------------------------------------------------
 // Get the current service routine
 
-void Cyg_Interrupt::get_vsr(cyg_vector vector, cyg_VSR **vsr)
+void
+Cyg_Interrupt::get_vsr(cyg_vector vector, cyg_VSR **vsr)
 {
     CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG2("vector = %d, mem to put VSR in is at %08x", vector,
+                        vsr);
 
-    CYG_ASSERT( vector >= CYG_VSR_MIN, "Invalid vector");        
-    CYG_ASSERT( vector <= CYG_VSR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_VSR_MIN, "Invalid vector");        
+    CYG_ASSERT( vector <= CYGNUM_HAL_VSR_MAX, "Invalid vector");
 
     HAL_VSR_GET( vector, vsr );
+
+    CYG_REPORT_RETURN();
 }
 
 // -------------------------------------------------------------------------
 // Install a vector service routine
 
-void Cyg_Interrupt::set_vsr(cyg_vector vector, cyg_VSR *vsr, cyg_VSR **old)
+void
+Cyg_Interrupt::set_vsr(cyg_vector vector, cyg_VSR *vsr, cyg_VSR **old)
 {
     CYG_REPORT_FUNCTION();
 
+    CYG_REPORT_FUNCARG3( "vector = %d, new vsr is at %08x, mem to put "
+                         "old VSR in is at %08x", vector, vsr, old);
+
     CYG_INSTRUMENT_INTR(SET_VSR, vector, vsr);
 
-    CYG_ASSERT( vector >= CYG_VSR_MIN, "Invalid vector");    
-    CYG_ASSERT( vector <= CYG_VSR_MAX, "Invalid vector");    
+    CYG_ASSERT( vector >= CYGNUM_HAL_VSR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_VSR_MAX, "Invalid vector");    
 
     CYG_INTERRUPT_STATE old_ints;
     
@@ -422,78 +506,103 @@ void Cyg_Interrupt::set_vsr(cyg_vector v
     HAL_VSR_SET( vector, vsr, old );
     
     HAL_RESTORE_INTERRUPTS(old_ints);
+
+    CYG_REPORT_RETURN();
 }
 
 // -------------------------------------------------------------------------
 // Disable interrupts at the CPU
 
 
-void Cyg_Interrupt::disable_interrupts()
+void
+Cyg_Interrupt::disable_interrupts(void)
 {
     CYG_REPORT_FUNCTION();
 
-    CYG_INSTRUMENT_INTR(DISABLE, 0, 0);
+    CYG_INSTRUMENT_INTR(DISABLE, disable_counter+1, 0);
 
     CYG_INTERRUPT_STATE dummy;
 
     HAL_DISABLE_INTERRUPTS(dummy);
 
-    // Keep a disable level counter??
+    CYG_ASSERT( disable_counter >= 0 , "Disable counter negative");
+    
+    disable_counter++;
+    
+    CYG_REPORT_RETURN();
 }
 
 
 // -------------------------------------------------------------------------
 // Re-enable CPU interrupts
 
-void Cyg_Interrupt::enable_interrupts()
+void
+Cyg_Interrupt::enable_interrupts(void)
 {
     CYG_REPORT_FUNCTION();
         
-    CYG_INSTRUMENT_INTR(ENABLE, 0, 0);
+    CYG_INSTRUMENT_INTR(ENABLE, disable_counter, 0);
+
+    CYG_ASSERT( disable_counter > 0 , "Disable counter not greater than zero");
+    
+    disable_counter--;
 
-    HAL_ENABLE_INTERRUPTS();
+    if ( disable_counter == 0 )
+    {
+        HAL_ENABLE_INTERRUPTS();
+    }
+
+    CYG_REPORT_RETURN();
 }
     
 // -------------------------------------------------------------------------
 // Mask a specific interrupt in a PIC
 
-void Cyg_Interrupt::mask_interrupt(cyg_vector vector)
+void
+Cyg_Interrupt::mask_interrupt(cyg_vector vector)
 {
     CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG1("vector=%d", vector);
 
-    CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector");    
-    CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
 
     CYG_INSTRUMENT_INTR(MASK, vector, 0);
 
-    HAL_INTERRUPT_MASK( vector )
+    HAL_INTERRUPT_MASK( vector );
+
+    CYG_REPORT_RETURN();
 }
 
 // -------------------------------------------------------------------------
 // Clear PIC mask
 
-void Cyg_Interrupt::unmask_interrupt(cyg_vector vector)
+void
+Cyg_Interrupt::unmask_interrupt(cyg_vector vector)
 {
     CYG_REPORT_FUNCTION();
 
-    CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector");    
-    CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
     
     CYG_INSTRUMENT_INTR(UNMASK, vector, 0);
 
     HAL_INTERRUPT_UNMASK( vector );
+
+    CYG_REPORT_RETURN();
 }
     
 
 // -------------------------------------------------------------------------
 // Acknowledge interrupt at PIC
 
-void Cyg_Interrupt::acknowledge_interrupt(cyg_vector vector)
+void
+Cyg_Interrupt::acknowledge_interrupt(cyg_vector vector)
 {
 //    CYG_REPORT_FUNCTION();
 
-    CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector");    
-    CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
 
     CYG_INSTRUMENT_INTR(ACK, vector, 0);
 
@@ -503,20 +612,25 @@ void Cyg_Interrupt::acknowledge_interrup
 // -------------------------------------------------------------------------
 // Change interrupt detection at PIC
 
-void Cyg_Interrupt::configure_interrupt(
+void
+Cyg_Interrupt::configure_interrupt(
     cyg_vector vector,              // vector to control
     cyg_bool level,                 // level or edge triggered
     cyg_bool up                     // hi/lo level, rising/falling edge
     )
 {
     CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG3("vector = %d, level = %d, up = %d", vector, level,
+                        up);
 
-    CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector");    
-    CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector");
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
 
     CYG_INSTRUMENT_INTR(CONFIGURE, vector, (level<<1)|up);
 
     HAL_INTERRUPT_CONFIGURE( vector, level, up );
+
+    CYG_REPORT_RETURN();
 }
 
 // -------------------------------------------------------------------------