diff packages/hal/common/current/src/drv_api.c @ 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
children d376b777e2ce
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/hal/common/current/src/drv_api.c
@@ -0,0 +1,706 @@
+//==========================================================================
+//
+//      drv_api.c
+//
+//      Driver API for non-kernel configurations
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998, 1999 Cygnus Solutions.  
+// All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   Nick Garnett
+// Date:        1999-02-24
+// Purpose:     Driver API for non-kernel configurations
+// Description: These functions are used to support drivers when the kernel
+//              is not present.
+//              
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+
+#ifndef CYGPKG_KERNEL
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/cyg_ass.h>
+
+#include <pkgconf/hal.h>
+#include <cyg/hal/drv_api.h>
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+
+//--------------------------------------------------------------------------
+// Statics
+
+static volatile cyg_int32 isr_disable_counter;  // ISR disable counter
+
+volatile cyg_int32 dsr_disable_counter asm("cyg_scheduler_sched_lock");  // DSR disable counter
+
+static volatile cyg_interrupt *dsr_list;        // List of pending DSRs
+
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+
+cyg_interrupt *chain_list[CYGNUM_HAL_ISR_COUNT];
+
+#endif
+
+//--------------------------------------------------------------------------
+// DSR handling functions.
+// post_dsr() places a DSR on the list of DSRs to be called.
+// call_dsrs() calls the DSRs.
+
+static void post_dsr( cyg_interrupt *intr )
+{
+    CYG_INTERRUPT_STATE old_intr;
+
+    CYG_REPORT_FUNCTION();
+
+    HAL_DISABLE_INTERRUPTS(old_intr);
+
+        if( intr->dsr_count++ == 0 )
+    {
+        intr->next_dsr = dsr_list;
+        dsr_list = intr;
+    }
+
+    HAL_RESTORE_INTERRUPTS(old_intr);
+
+    CYG_REPORT_RETURN();    
+}
+
+static void call_dsrs(void)
+{
+    CYG_REPORT_FUNCTION();
+    
+    while( dsr_list != NULL )
+    {
+        volatile cyg_interrupt *intr;
+        cyg_int32 count;
+        CYG_INTERRUPT_STATE old_intr;
+
+        HAL_DISABLE_INTERRUPTS(old_intr);
+        
+        intr = dsr_list;
+        dsr_list = intr->next_dsr;
+        count = intr->dsr_count;
+        intr->dsr_count = 0;
+        
+        HAL_RESTORE_INTERRUPTS(old_intr);
+
+        intr->dsr( intr->vector, count, (CYG_ADDRWORD)intr->data );
+    }
+
+    CYG_REPORT_RETURN();
+    
+}
+
+//--------------------------------------------------------------------------
+// Interrupt end function called from HAL VSR to tidy up. This is where
+// DSRs will be called if necessary.
+
+externC void
+interrupt_end(
+    cyg_uint32          isr_ret,
+    cyg_interrupt       *intr,
+    HAL_SavedRegisters  *regs
+    )
+{
+    CYG_REPORT_FUNCTION();
+    
+#ifndef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+
+    // Only do this if we are in a non-chained configuration.
+    // If we are chained, then chain_isr will do the DSR
+    // posting.
+    
+    if( isr_ret & CYG_ISR_CALL_DSR && intr != NULL ) post_dsr(intr);
+
+#endif
+
+    if( dsr_disable_counter == 0 ) call_dsrs();
+
+    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// ISR for handling chained interrupts.
+
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+
+cyg_uint32 chain_isr(cyg_vector_t vector, CYG_ADDRWORD data)
+{
+    CYG_REPORT_FUNCTION();
+ 
+    cyg_interrupt *p = *(cyg_interrupt **)data;
+
+    while( p != NULL )
+    {
+        if( p->vector == vector )
+        {
+            register cyg_uint32 isr_ret = p->isr(vector, p->data);
+
+            if( isr_ret & CYG_ISR_CALL_DSR ) post_dsr(p);
+
+            if( isr_ret & CYG_ISR_HANDLED ) break;
+        }
+
+        p = p->next;
+    }
+
+    CYG_REPORT_RETURN();
+    
+    return 0;
+}
+
+#endif
+
+//--------------------------------------------------------------------------
+// ISR lock. This disables interrupts and keeps a count of the number
+// times it has been called.
+
+externC void cyg_drv_isr_lock()
+{
+    CYG_INTERRUPT_STATE dummy;
+
+    CYG_REPORT_FUNCTION();
+
+    HAL_DISABLE_INTERRUPTS(dummy);
+
+    CYG_ASSERT( isr_disable_counter >= 0 , "Disable counter negative");
+    
+    isr_disable_counter++;
+    
+    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// Unlock ISRs. This decrements the count and re-enables interrupts if it
+// goes zero.
+
+externC void cyg_drv_isr_unlock()
+{
+    CYG_REPORT_FUNCTION();
+        
+    CYG_ASSERT( isr_disable_counter > 0 , "Disable counter not greater than zero");
+    
+    isr_disable_counter--;
+
+    if ( isr_disable_counter == 0 )
+    {
+        HAL_ENABLE_INTERRUPTS();
+    }
+
+    CYG_REPORT_RETURN();
+}
+
+//--------------------------------------------------------------------------
+// Lock DSR lock. Simply increment the counter.
+
+externC void cyg_drv_dsr_lock()
+{
+    CYG_REPORT_FUNCTION();
+
+    dsr_disable_counter++;
+
+    CYG_REPORT_RETURN();
+}
+
+//--------------------------------------------------------------------------
+// Unlock DSR lock. If the counter is about to go zero, call any pending
+// DSRs and then zero the counter.
+
+externC void cyg_drv_dsr_unlock()
+{
+    CYG_REPORT_FUNCTION();
+
+    do
+    {
+        if( dsr_disable_counter == 1 )
+        {
+            call_dsrs();
+        }
+
+        HAL_REORDER_BARRIER();
+        
+        dsr_disable_counter = 0;
+
+        HAL_REORDER_BARRIER();
+
+        // Check that no DSRs have been posted between calling
+        // call_dsrs() and zeroing dsr_disable_counter. If so,
+        // loop back and call them.
+        
+        if( dsr_list != NULL )
+        {
+            dsr_disable_counter = 1;
+            continue;
+        }
+
+        CYG_REPORT_RETURN();
+        
+        return;
+        
+    } while(1);
+
+    CYG_FAIL( "Should not be executed" );
+}
+
+//--------------------------------------------------------------------------
+// Initialize a mutex.
+
+externC void cyg_drv_mutex_init( cyg_drv_mutex_t *mutex )
+{
+    CYG_REPORT_FUNCTION();
+    
+    mutex->lock = 0;
+
+    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// Destroy a mutex.
+
+externC void cyg_drv_mutex_destroy( cyg_drv_mutex_t *mutex )
+{
+    CYG_REPORT_FUNCTION();
+    
+    mutex->lock = -1;
+
+    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// Lock a mutex. We check that we are not trying to lock a locked or
+// destroyed mutex and if not, set it locked.
+
+externC cyg_bool_t cyg_drv_mutex_lock( cyg_drv_mutex_t *mutex )
+{
+    CYG_REPORT_FUNCTION();
+    
+    CYG_ASSERT( mutex->lock == 0 , "Trying to lock locked mutex");
+
+    mutex->lock = 1;
+
+    CYG_REPORT_RETURN();
+
+    return true;
+}
+
+//--------------------------------------------------------------------------
+// Attempt to claim a mutex, and return if it cannot be.
+
+externC cyg_bool_t cyg_drv_mutex_trylock( cyg_drv_mutex_t *mutex )
+{
+    cyg_bool_t result = true;
+    
+    CYG_REPORT_FUNCTION();
+
+    if( mutex->lock == 1 ) result = false;
+    
+    CYG_REPORT_RETURN();
+
+    return result;
+}
+
+//--------------------------------------------------------------------------
+// Unlock a mutex. We check that the mutex is actually locked before doing
+// this.
+
+externC void cyg_drv_mutex_unlock( cyg_drv_mutex_t *mutex )
+{
+    CYG_REPORT_FUNCTION();
+
+    CYG_ASSERT( mutex->lock == 1 , "Trying to unlock unlocked mutex");
+
+    mutex->lock = 0;
+    
+    CYG_REPORT_RETURN();    
+}
+    
+//--------------------------------------------------------------------------
+// Release all threads waiting for the mutex.
+// This is really for threads, so we do nothing here.
+
+externC void cyg_drv_mutex_release( cyg_drv_mutex_t *mutex )
+{
+    CYG_REPORT_FUNCTION();
+
+
+    
+    CYG_REPORT_RETURN();    
+}
+    
+
+//--------------------------------------------------------------------------
+// Initialized a condition variable.
+
+externC void cyg_drv_cond_init( cyg_drv_cond_t  *cond, cyg_drv_mutex_t *mutex )
+{
+    CYG_REPORT_FUNCTION();
+
+    cond->wait = 0;
+    cond->mutex = mutex;
+    
+    CYG_REPORT_RETURN();    
+}
+    
+
+//--------------------------------------------------------------------------
+// Destroy a condition variable.
+
+externC void cyg_drv_cond_destroy( cyg_drv_cond_t  *cond )
+{
+    CYG_REPORT_FUNCTION();
+
+    cond->wait = -1;
+    cond->mutex = NULL;
+    
+    CYG_REPORT_RETURN();    
+}
+    
+// -------------------------------------------------------------------------
+// Wait for a condition variable to be signalled. We simply busy wait
+// polling the condition variable's wait member until a DSR sets it to
+// 0.  Note that the semantics of condition variables means that the
+// wakeup only happens if there is a thread actually waiting on the CV
+// when the signal is sent.
+
+externC void cyg_drv_cond_wait( cyg_drv_cond_t *cond )
+{
+    CYG_REPORT_FUNCTION();
+
+    CYG_ASSERT( cond->mutex != NULL, "Uninitialized condition variable");
+    CYG_ASSERT( cond->mutex->lock, "Mutex not locked");
+
+    cyg_drv_dsr_lock();
+    
+    cond->wait = 1;
+       
+    while( cond->wait == 1 )
+    {
+        // While looping we call call_dsrs() to service any DSRs that
+        // get posted. One of these will make the call to cond_signal
+        // to break us out of this loop. If we do not have the DSR
+        // lock claimed, then a race condition could occur and keep us
+        // stuck here forever.
+        
+        call_dsrs();
+    }
+
+    cyg_drv_dsr_unlock();
+    
+    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// Signal a condition variable. This sets the wait member to zero, which
+// has no effect when there is no waiter, but will wake up any waiting
+// thread.
+
+externC void cyg_drv_cond_signal( cyg_drv_cond_t *cond )
+{
+    CYG_REPORT_FUNCTION();
+
+    cond->wait = 0;
+    
+    CYG_REPORT_RETURN();    
+}
+    
+
+//--------------------------------------------------------------------------
+// Broadcast to condition variable. This is exactly the same a signal since
+// there can only be one waiter.
+
+externC void cyg_drv_cond_broadcast( cyg_drv_cond_t *cond )
+{
+    CYG_REPORT_FUNCTION();
+
+    cond->wait = 0;
+    
+    CYG_REPORT_RETURN();    
+}
+    
+
+//--------------------------------------------------------------------------
+// Create an interrupt object.
+
+externC void cyg_drv_interrupt_create(
+                     cyg_vector_t        vector,
+                     cyg_priority_t      priority,
+                     cyg_addrword_t      data,
+                     cyg_ISR_t           *isr,
+                     cyg_DSR_t           *dsr,
+                     cyg_handle_t        *handle,
+                     cyg_interrupt       *intr
+                     )
+{
+    CYG_REPORT_FUNCTION();
+
+    intr->vector        = vector;
+    intr->priority      = priority;
+    intr->isr           = isr;
+    intr->dsr           = dsr;
+    intr->data          = data;
+    intr->next_dsr      = NULL;
+    intr->dsr_count     = 0;
+
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+
+    intr->next          = NULL;
+    
+#endif    
+
+    *handle = (cyg_handle_t)intr;
+    
+    CYG_REPORT_RETURN();
+}
+
+//--------------------------------------------------------------------------
+// Delete an interrupt object. This merely ensures that it is detached from
+// the vector.
+
+externC void cyg_drv_interrupt_delete( cyg_handle_t interrupt )
+{
+    CYG_REPORT_FUNCTION();
+
+    cyg_drv_interrupt_detach( interrupt );
+    
+    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// 
+
+externC void cyg_drv_interrupt_attach( cyg_handle_t interrupt )
+{
+    cyg_interrupt *intr = (cyg_interrupt *)interrupt;
+    
+    CYG_REPORT_FUNCTION();
+
+    CYG_ASSERT( intr->vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+    CYG_ASSERT( intr->vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+    HAL_INTERRUPT_SET_LEVEL( intr->vector, intr->priority );
+    
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+
+    CYG_ASSERT( intr->next == NULL , "cyg_interrupt already on a list");
+
+    cyg_uint32 index;
+
+    HAL_TRANSLATE_VECTOR( intr->vector, index );
+
+    if( chain_list[index] == NULL )
+    {
+        // First Interrupt on this chain, just assign it and register
+        // the chain_isr with the HAL.
+        
+        chain_list[index] = intr;
+
+        HAL_INTERRUPT_ATTACH( intr->vector, chain_isr, &chain_list[index], NULL );
+    }
+    else
+    {
+        // There are already interrupts chained, add this one into the
+        // chain in priority order.
+        
+        Cyg_Interrupt **p = &chain_list[index];
+
+        while( *p != NULL )
+        {
+            cyg_interrupt *n = *p;
+
+            if( n->priority < intr->priority ) break;
+            
+            p = &n->next;
+        }
+        next = *p;
+        *p = intr;
+    }
+    
+#else
+    
+    HAL_INTERRUPT_ATTACH( intr->vector, intr->isr, intr->data, intr );
+
+#endif    
+    
+    CYG_REPORT_RETURN();    
+}
+   
+
+//--------------------------------------------------------------------------
+// Detach an interrupt from its vector.
+
+externC void cyg_drv_interrupt_detach( cyg_handle_t interrupt )
+{
+    cyg_interrupt *intr = (cyg_interrupt *)interrupt;
+    
+    CYG_REPORT_FUNCTION();
+
+    CYG_ASSERT( intr->vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( intr->vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+
+    // Remove the interrupt object from the vector chain.
+    
+    cyg_uint32 index;
+
+    HAL_TRANSLATE_VECTOR( vector, index );
+
+    cyg_interrupt **p = &chain_list[index];
+
+    while( *p != NULL )
+    {
+        cyg_interrupt *n = *p;
+
+        if( n == intr )
+        {
+            *p = intr->next;
+            break;
+        }
+            
+        p = &n->next;
+    }
+
+    // If this was the last one, detach the vector.
+    
+    if( chain_list[index] == NULL )
+        HAL_INTERRUPT_DETACH( intr->vector, chain_isr );
+    
+#else
+    
+    HAL_INTERRUPT_DETACH( intr->vector, intr->isr );
+
+#endif
+    
+    CYG_REPORT_RETURN();    
+}
+    
+
+//--------------------------------------------------------------------------
+// Mask delivery of an interrupt at the interrupt controller.
+
+externC void cyg_drv_interrupt_mask( cyg_vector_t vector )
+{
+    CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG1("vector=%d", vector);
+
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+    HAL_INTERRUPT_MASK( vector );
+
+    CYG_REPORT_RETURN();
+}
+
+//--------------------------------------------------------------------------
+// Unmask delivery of an interrupt at the interrupt controller.
+
+externC void cyg_drv_interrupt_unmask( cyg_vector_t vector )
+{
+    CYG_REPORT_FUNCTION();
+
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+    
+    HAL_INTERRUPT_UNMASK( vector );
+
+    CYG_REPORT_RETURN();
+}
+
+//--------------------------------------------------------------------------
+// Acknowledge an interrupt at the controller to allow another interrupt
+// to be delivered.
+
+externC void cyg_drv_interrupt_acknowledge( cyg_vector_t vector )
+{
+//    CYG_REPORT_FUNCTION();
+
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+    HAL_INTERRUPT_ACKNOWLEDGE( vector );
+
+//    CYG_REPORT_RETURN();    
+}
+
+//--------------------------------------------------------------------------
+// Configure interrupt detection parameters.
+
+externC void cyg_drv_interrupt_configure(
+                     cyg_vector_t        vector,
+                     cyg_bool_t          level,
+                     cyg_bool_t          up
+                     )
+{
+    CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG3("vector = %d, level = %d, up = %d", vector, level,
+                        up);
+
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+    HAL_INTERRUPT_CONFIGURE( vector, level, up );
+
+    CYG_REPORT_RETURN();
+}
+
+//--------------------------------------------------------------------------
+// Configure interrupt priority level.
+
+externC void cyg_drv_interrupt_level( cyg_vector_t vector, cyg_priority_t level )
+{
+    CYG_REPORT_FUNCTION();
+    CYG_REPORT_FUNCARG2("vector = %d, level = %d", vector, level);
+
+    CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");    
+    CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+    HAL_INTERRUPT_SET_LEVEL( vector, level );
+
+    CYG_REPORT_RETURN();
+}
+
+
+// -------------------------------------------------------------------------
+// Exception delivery function called from the HAL as a result of a
+// hardware exception being raised.
+
+externC void cyg_hal_deliver_exception( CYG_WORD code, CYG_ADDRWORD data )
+{
+    CYG_FAIL(" !!! Exception !!! ");
+}
+
+
+#endif
+
+//--------------------------------------------------------------------------
+// EOF drv_api.c