#define OSRES_C
/******************************************************************************
 *
 *       (C) Copyright 2006, Freescale Semiconductor, Inc. All Rights Reserved.
 *
 *       THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
 *       BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
 *       Freescale Semiconductor, Inc.
 *
 * Filename:     $Source: /u/OSEK/src/os2000/src/osesys/src/osres.c,v $
 * Author:       $Author: c-atroshikhin $
 * Revision:     $Revision: 1.10 $
 *
 * Functions:    
 *
 * History:      Use the CVS command rlog to display revision history
 *               information.
 *
 * Description:  Function code to support OSEK OS resources  
 *
 * Notes:        
 *
 ******************************************************************************/

#if !defined(OSPROPH)
#include "osprop.h"                     /* OS Properties */
#else                                   /* !defined(OSPROPH)    */
#include OSPROPH                        /* OS Properties */
#endif                                  /* !defined(OSPROPH)    */

#include <osapi.h>                      /* Types and constants  */

/*  Conditional compilation */
/*  Resource management */

/*  Global OS variables */

/*  Private OS Services */
#if defined(OSRES_SCHEDULER)
#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
OSRESCB OsResScheduler;
#endif                                  /* defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)        */
#endif                                  /* defined(OSRES_SCHEDULER) */

#if defined(OSRESOURCE)

OSRESCB OsResources[OSNALLRES];
#if defined(OSRESOURCEISR)
ResourceType OsISRLastResource;         /* The head of ISRs resource list         */
#endif                                  /* defined(OSRESOURCEISR) */

/***************************************************************************
 * Function : OSGetResource
 *
 * Description:
 *
 * Returns: Status E_OK
 *
 * Notes:   Assumption: running task that gets resource is 
 *          always first in ready list (OsRunning)
 *
 **************************************************************************/

StatusType OSGetResource( ResourceType resId )
{
  volatile OSINTMASKTYPE msr;
  OSVIMSAVE                             /* volatile OSINTMASKTYPE save; */
  OSBYTE resLevel;
#if defined(OSEXTSTATUS)
  OSSIGNEDDWORD i;

  OSOrtiSetServiceWatch( OSServiceId_GetResource );
  for( i = 0; i < OSNALLRES; i++ )
  {
    if( resId == &OsResources[i] )
    {
      break;
    }
  }
  if( i == OSNALLRES )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetResource, resId );
  }
  if( resId->isUsed )
  {                                     /* attempt to access occupied resource  */
    OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, resId );
  }
#if defined(OSISRENTRYEXIT)
  if( OSISRLEVEL != 0 )                 /* Check call level */
  {
#if defined(OSRESOURCEISR)
    if( resId->prio < 0 )               /* prio < 0 - ISR resource */
    {
#if defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) || \
        (defined(OSEXTSTATUS) && defined(OSRESOURCEISR))
#if defined(OSHIGHESTISRPRIO)
      if( OsSivecPtr == &OsDecSivec )   /* current ISR is the DEC ISR */
      {
        if( -resId->prio != OSMAXISRLEVEL ) /* resource priority is not DEC priority */
        {                               /* resource priority is lower than assigned ISR priority */
          OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, resId );
        }
      }
      else
#endif                                  /* defined(OSHIGHESTISRPRIO) */
      {
        if( OSINTC_CPR > (-resId->prio) )
        {                               /* resource priority is lower than assigned ISR priority */
          OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, resId );
        }
      }
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) || \*/
      /* (defined(OSEXTSTATUS) && defined(OSRESOURCEISR)) */
    }
    else
#endif                                  /* defined(OSRESOURCEISR) */
    {
      /* resource is not for ISR */
      OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, resId );
    }
  }
#endif                                  /* defined(OSISRENTRYEXIT) */
#if defined(OSRESOURCEISR)
  if( resId->prio >= 0)                 /* prio >= 0 - TASK resource */
#endif                                  /* defined(OSRESOURCEISR) */
  {
    if( OsRunning->taskId < resId->prio )
    {                                   /* or resource with lower priority      */
      OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, resId );
    }
  }
#else                                   /* defined(OSEXTSTATUS) */
  OSOrtiSetServiceWatch( OSServiceId_GetResource );
#if defined(OSRESOURCEISR)
#if !defined(OSWITHINTERRUPTLEVEL) && !defined(OSISRENHANCED) && (OSORTIDEBUGLEVEL == 0)
  if( OSISRLEVEL != 0 )                 /* Check call level     */
  {
    OSOrtiServiceWatchOnExit( OSServiceId_GetResource );
    return E_OK;                        /* nothing to do in ISR */
  }
#endif                                  /* !defined(OSWITHINTERRUPTLEVEL) && !defined(OSISRENHANCED) && (OSORTIDEBUGLEVEL == 0) */
#endif                                  /* defined(OSRESOURCEISR) */

#endif                                  /* defined(OSEXTSTATUS) */
  OSDIR( save, msr );

#if defined(OSRESOURCEISR)
  if( resId->prio < 0)                  /* prio < 0 - ISR resource */
  {
    if( OsIsrLevel == 0 )               /* It is not necessary to block schduler on ISR level */
    {
      OsIsrLevel |= OSISRRESOURCELEVEL; /* block scheduler */
    }
#if defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED)
#if defined(OSHIGHESTISRPRIO)
    if( -(resId->prio) == OSMAXISRLEVEL ) /* ISR resource for DEC */
    {
      resId->savedIsrMask = msr;
      OSSAVEDMSR(msr) &= ~( OSMSR_EE ); /* clear EI bit */
      OsIsrLevel |= OSISRRESOURCEHIGHESTLEVEL;
    }
    else
#endif                                  /* defined(OSHIGHESTISRPRIO) */
    {
      resId->savedIsrMask = save;
      OSSIMASKPrepare(save, -(resId->prio));

      if( OSISRMASKFIRSTMORETHENSECOND(save, resId->savedIsrMask))
      {
        OSISRMASKCOPYFIRST2SECOND(resId->savedIsrMask, save);
      }
    }
#else                                   /* defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) */
    if( OsISRLastResource == OSNULLRES ) /* It is the first ISR resource */
    {
      resId->savedIsrMask = save;
      save &= ~( OSMSR_EE | OSMSR_CI ); /* clear EI bit */
    }
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) */
#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
    resId->isUsed = 1;
#endif                                  /* defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0) */
#if defined(OSEXTSTATUS)
    resId->nextRes = OsISRLastResource;
#else                                   /* defined(OSEXTSTATUS)*/
    resId->prio2task = (OSTSKCBPTR)OsISRLastResource;
#endif                                  /* defined(OSEXTSTATUS) */
    OsISRLastResource = resId;
  }
  else                                  /* Task level resource */
#endif                                  /* defined(OSRESOURCEISR) */
  {
    resId->prio2task = OSGETTASK(resId->prio);
    OSGETTASK(resId->prio) = OsRunning;

    OSTask2Ready(resId->prio);

#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
    resId->isUsed = 1;
#if defined(OSEXTSTATUS)
    resId->nextRes = OsRunning->resources;
    OsRunning->resources = resId;
#endif                                  /* defined(OSEXTSTATUS) */
#endif                                  /* defined(OSEXTSTATUS) */
  }
#if (OSORTIDEBUGLEVEL > 0)
  resId->curPrio = OsRunning->curPrio; /* save the current task prio value */
#if defined(OSRES_SCHEDULER)
  if( ((OsRunning->curPrio == OsResScheduler.prio) && (resId->prio < 0)) || \
     ((OsRunning->curPrio != OsResScheduler.prio) && (OsRunning->curPrio >
     resId->prio)) )
#else                                   /* defined(OSRES_SCHEDULER) */
  if( OsRunning->curPrio > resId->prio )
#endif                                  /* defined(OSRES_SCHEDULER) */
  {
    OsRunning->curPrio = resId->prio;
  }
#endif                                  /* (OSORTIDEBUGLEVEL > 0) */
  OSRIR( save, msr );
  OSOrtiServiceWatchOnExit( OSServiceId_GetResource );
  return( E_OK );
}

/***************************************************************************
 * Function : OSReleaseResource
 *
 * Description:
 *
 * Returns: Status E_OK
 *
 * Notes:   Assumption: running task that releases resource is 
 *          always first in ready list (OsRunning)
 *
 **************************************************************************/

StatusType OSReleaseResource( ResourceType resId )
{
  volatile OSINTMASKTYPE msr;
  OSVIMSAVE                             /* volatile OSINTMASKTYPE save; */
  OSBYTE resLevel;
#if defined(OSEXTSTATUS)
  OSSIGNEDDWORD i;

  OSOrtiSetServiceWatch( OSServiceId_ReleaseResource );
  for( i = 0; i < OSNALLRES; i++ )
  {
    if( resId == &OsResources[i] )
    {
      break;
    }
  }
  if( i == OSNALLRES )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_ReleaseResource, resId );
  }
  if( !(resId->isUsed) )
  {                                     /* attempt to access not occupied resource  */
    OSRETERROR( E_OS_NOFUNC, OSServiceId_ReleaseResource, resId );
  }
#if defined(OSRESOURCEISR)
  if( resId->prio < 0 )                 /* ISR resource */
  {
    if( OsISRLastResource != resId )
    {                                   /* another resource have to be released before */
      OSRETERROR( E_OS_NOFUNC, OSServiceId_ReleaseResource, resId );
    }
#if defined(OSISRENTRYEXIT)
    if( OSISRLEVEL != 0 )               /* Check call level */
    {                                   /* resource is not for ISR */
#if defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) || \
        (defined(OSEXTSTATUS) && defined(OSRESOURCEISR))
#if defined(OSHIGHESTISRPRIO)
      if( OsSivecPtr == &OsDecSivec )   /* current ISR is the DEC ISR */
      {
        if( -resId->prio != OSMAXISRLEVEL ) /* resource priority is not DEC priority */
        {                               /* resource priority is lower than assigned ISR priority */
          OSRETERROR( E_OS_ACCESS, OSServiceId_ReleaseResource, resId );
        }
      }
      else
#endif                                  /* defined(OSHIGHESTISRPRIO) */
      {
        if( OSINTC_CPR > (-resId->prio) )
        {                               /* resource priority is lower than assigned ISR priority */
          OSRETERROR( E_OS_ACCESS, OSServiceId_ReleaseResource, resId );
        }
      }
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) || \ */
      /* (defined(OSEXTSTATUS) && defined(OSRESOURCEISR)) */
    }
#endif                                  /* defined(OSISRENTRYEXIT) */
  }
  else                                  /* TASK resource */
#endif                                  /* defined(OSRESOURCEISR) */
  {
    if( OsRunning->resources != resId )
    {                                   /* another resource have to be released before */
      OSRETERROR( E_OS_NOFUNC, OSServiceId_ReleaseResource, resId );
    }
#if defined(OSISRENTRYEXIT)
    if( OSISRLEVEL != 0 )               /* Check call level */
    {                                   /* resource is not for ISR */
      OSRETERROR( E_OS_ACCESS, OSServiceId_ReleaseResource, resId );
    }
#endif                                  /* defined(OSISRENTRYEXIT) */
    if( OsRunning->taskId < resId->prio )
    {                                   /* or resource with lower priority      */
      OSRETERROR( E_OS_ACCESS, OSServiceId_ReleaseResource, resId );
    }
  }
#else                                   /* defined(OSEXTSTATUS) */
  OSOrtiSetServiceWatch( OSServiceId_ReleaseResource );
#if defined(OSRESOURCEISR)
#if !defined(OSWITHINTERRUPTLEVEL) && !defined(OSISRENHANCED) && (OSORTIDEBUGLEVEL == 0)
  if( OSISRLEVEL != 0 )                 /* Check call level     */
  {
    OSOrtiServiceWatchOnExit( OSServiceId_ReleaseResource );
    return E_OK;                        /* nothing to do in ISR */
  }
#endif                                  /* !defined(OSWITHINTERRUPTLEVEL) && !defined(OSISRENHANCED) && (OSORTIDEBUGLEVEL == 0) */
#endif                                  /* defined(OSRESOURCEISR) */

#endif                                  /* defined(OSEXTSTATUS) */
  OSDIR( save, msr );
  OSOrtiSetOldServiceID( OSServiceId_ReleaseResource );
#if defined(OSRESOURCEISR)
  if( resId->prio < 0 )                 /* prio < 0 - ISR resource */
  {
#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
    resId->isUsed = 0;
#endif                                  /* defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0) */
#if defined(OSEXTSTATUS)
    OsISRLastResource = resId->nextRes;
#else                                   /* defined(OSEXTSTATUS) */
    OsISRLastResource = (ResourceType)resId->prio2task;
#endif                                  /* defined(OSEXTSTATUS) */
#if defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED)
#if defined(OSHIGHESTISRPRIO)
    if( -(resId->prio) == OSMAXISRLEVEL ) /* ISR resource for DEC */
    {
      msr = resId->savedIsrMask;
    }
    else
#endif                                  /* defined(OSHIGHESTISRPRIO) */
    {
      save = resId->savedIsrMask;
    }
#else                                   /* defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) */
    if( OsISRLastResource == OSNULLRES ) /* It is the first ISR resource */
    {
      save = resId->savedIsrMask;       /* restore MSR */
    }
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) || defined(OSISRENHANCED) */
    if( OsISRLastResource == OSNULLRES ) /* It is the first ISR resource */
    {
      if( OSISRLEVEL == 0 )             /* its is not necessary to unblock scheduler on ISR level */
      {
        OsIsrLevel &= ~OSISRRESOURCELEVEL; /* unblock scheduler */
      }
    }
  }
  else
#endif                                  /* defined(OSRESOURCEISR) */
  {
    OSGETTASK(resId->prio) = resId->prio2task;

#if defined(OSECC)
    if(( OSTASKSTATUS(resId->prio)
      & (OSTCBNOSUSPENDED | OSTCBWAIT)) != OSTCBNOSUSPENDED )
#else                                   /* defined(OSECC) */
    if( (OSTASKSTATUS(resId->prio) & OSTCBNOSUSPENDED) == 0 )
#endif                                  /* defined(OSECC) */
    {
      OSTask2Suspend(resId->prio);
    }
#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
    resId->isUsed = 0;
#endif                                  /* defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0) */
#if defined(OSEXTSTATUS)
    OsRunning->resources = resId->nextRes;
#endif                                  /* defined(OSEXTSTATUS) */
  }
#if (OSORTIDEBUGLEVEL > 0)
  if( OsRunning->curPrio < resId->curPrio )
  {
    OsRunning->curPrio = resId->curPrio;
  }
#endif                                  /* (OSORTIDEBUGLEVEL > 0) */
#if defined(OSISRNORMAL)
  if( OsIsrLevel == 0)
#endif                                  /* defined(OSISRNORMAL) */
  {                                     /* Rescheduling may be executed on the task level only */
    if( OsRunning != OSGETTASK(OSGetReadyTask()) )
    {
      OSDISPATCH();
    }
  }
  OSOrtiResetIdOnExit();
  OSRIR( save, msr );
  return( E_OK );
}
#endif                                  /* defined(OSRESOURCE) */

#if defined(OSRES_SCHEDULER)

/***************************************************************************
 * Function :  OSGetScheduler
 *
 * Description:
 *
 * Returns: Status E_OK
 *
 * Notes:   resId is checked only if there are no other resources,
 *          otherwise the check is done in GetResource 
 *
 **************************************************************************/

#if defined(OSRESOURCE) || !defined(OSEXTSTATUS)
StatusType OSGetScheduler( void )
#else
StatusType OSGetScheduler( ResourceType resId )
#endif
{
  OSIMSAVE                              /* OSINTMASKTYPE save;       */

  OSOrtiSetServiceWatch( OSServiceId_GetResource );
#if defined(OSEXTSTATUS)
#if !defined(OSRESOURCE)
  if( resId != RES_SCHEDULER )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetResource, resId );
  }
#endif
#if defined(OSISRENTRYEXIT)
  if( OSISRLEVEL != 0 )                 /* Check call level */
  {                                     /* resource is not for ISR */
    OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, RES_SCHEDULER );
  }
#endif                                  /* defined(OSISRENTRYEXIT) */
  if( (OSRUNNINGSTATUS & OSTCBSCHEDULER) != 0 )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_ACCESS, OSServiceId_GetResource, RES_SCHEDULER );
  }
#endif                                  /* defined(OSEXTSTATUS) */

  OSDIS( save );
  OSRUNNINGSTATUS |= OSTCBSCHEDULER;

#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
#if defined(OSEXTSTATUS)
  OsResScheduler.nextRes = OsRunning->resources;
  OsRunning->resources = RES_SCHEDULER;
#endif                                  /* defined(OSEXTSTATUS) */
  OsResScheduler.isUsed = 1;
#endif                                  /* defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0) */
#if defined(OSECC) || defined(OSRESOURCE) || defined(OSNOFASTTERMINATE)
#if (OSORTIDEBUGLEVEL > 0)
  if( OsRunning->curPrio >= 0)
  {
    OsResScheduler.curPrio = OsRunning->curPrio; /* save the current task prio value */
    OsRunning->curPrio = OsResScheduler.prio;
  }
#endif                                  /* (OSORTIDEBUGLEVEL > 0) */
#endif                                  /* defined(OSECC) || defined(OSRESOURCE) || defined(OSNOFASTTERMINATE) */
  OSRI( save );
  OSOrtiServiceWatchOnExit( OSServiceId_GetResource );
  return( E_OK );
}

/***************************************************************************
 * Function :  OSReleaseScheduler
 *
 * Description:
 *
 * Returns: Status E_OK
 *
 * Notes:   resId is checked only if there are no other resources,
 *          otherwise the check is done in ReleaseResource 
 *
 **************************************************************************/

#if defined(OSRESOURCE) || !defined(OSEXTSTATUS)
StatusType OSReleaseScheduler( void )
#else
StatusType OSReleaseScheduler( ResourceType resId )
#endif
{

  OSIMSAVE                              /* OSINTMASKTYPE save;       */
  OSUSETASK2READYCHECK

  OSOrtiSetServiceWatch( OSServiceId_ReleaseResource );
#if defined(OSEXTSTATUS)
#if !defined(OSRESOURCE)
  if( resId != RES_SCHEDULER )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_ReleaseResource, resId );
  }
#endif

  if( (OSRUNNINGSTATUS & OSTCBSCHEDULER) == 0 )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_NOFUNC, OSServiceId_ReleaseResource, RES_SCHEDULER );
  }
  if( OsRunning->resources != RES_SCHEDULER )
  {                                     /* another resource have to be released before */
    OSRETERROR( E_OS_NOFUNC, OSServiceId_ReleaseResource, RES_SCHEDULER );
  }
#if defined(OSISRENTRYEXIT)
  if( OSISRLEVEL != 0 )                 /* Check call level */
  {                                     /* resource is not for ISR */
    OSRETERROR( E_OS_ACCESS, OSServiceId_ReleaseResource, RES_SCHEDULER );
  }
#endif                                  /* defined(OSISRENTRYEXIT) */
#endif                                  /* defined(OSEXTSTATUS) */
  OSDIS( save );
  OSOrtiSetOldServiceID( OSServiceId_ReleaseResource );
  /* release scheduler    */
  OSRUNNINGSTATUS &= (OSBYTE)~OSTCBSCHEDULER;

#if defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0)
  OsResScheduler.isUsed = 0;
#if defined(OSEXTSTATUS)
  OsRunning->resources = OsResScheduler.nextRes;
#endif                                  /* defined(OSEXTSTATUS) */
#if defined(OSECC) || defined(OSRESOURCE) || defined(OSNOFASTTERMINATE)
#if (OSORTIDEBUGLEVEL > 0)
  if( OsRunning->curPrio == OsResScheduler.prio)
  {
    OsRunning->curPrio = OsResScheduler.curPrio;
  }
#endif                                  /* (OSORTIDEBUGLEVEL > 0) */
#endif                                  /* defined(OSECC) || defined(OSRESOURCE) || defined(OSNOFASTTERMINATE) */
#endif                                  /* defined(OSEXTSTATUS) || (OSORTIDEBUGLEVEL > 0) */

#if defined(OSISRNORMAL)
  if( OsIsrLevel == 0)
#endif                                  /* defined(OSISRNORMAL) */
  {
    if( OsRunning != OSGETMAXPRIOTASK )
    {
      OSDISPATCH();
    }
  }
  OSOrtiResetIdOnExit();
  OSRI( save );

  return( E_OK );
}
#endif                                  /* defined(OSRES_SCHEDULER) */
