/*
* Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.

* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA 
*/

//*****************************************************************************
//*    Routines related to timer management.  
//*****************************************************************************


#include "VSA2.H"
#include "CHIPSET.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "TIMER.H"

typedef   unsigned char (* TIMER_ON)(ULONG, UCHAR);
typedef   void (* TIMER_OFF)(unsigned short);


// External prototypes:
extern UCHAR EnableMsTimer_5536(ULONG, UCHAR);
extern USHORT DisableMsTimer_5536(USHORT);
extern void pascal MarkTimerAvailable(USHORT);


// External variables:
extern ULONG MsgPacket[];
extern EVENT_ENTRY Events[];
extern ULONG ClocksPerMs;
extern Hardware HardwareInfo;
extern TIMERS TimerInfo[];


// Local variables:
TIMER_ON  EnableTimer;
TIMER_OFF DisableTimer;
USHORT ActiveTimer;
ULONG ActiveInterval;


//***********************************************************************
// Performs initialization related to timers
//***********************************************************************
void InitTimers(void)
{

  switch (HardwareInfo.Chipset_ID) {

    case DEVICE_ID_5536:
      EnableTimer = EnableMsTimer_5536;
      DisableTimer = DisableMsTimer_5536;
      break;
  }
}



//***********************************************************************
// This routine handles timer ticks.
//***********************************************************************
USHORT FilterTimer(EVENT_ENTRY * EventPtr, EVENT EventIndex) 
{ USHORT ReturnValue=0;
  ULONG Vsm;
  static EVENT NextToExpire;

  Vsm = EventPtr->Vsm;


  // If 1st registered timer, initialize 'next interval' variables
  if (EventIndex == EVENT_TIMER) {
    NextToExpire = 0;
  }

  // Only decrement timers associated with the expired h/w timer
  if (EventPtr->Timer == ActiveTimer) {

    // Has this timer expired ?
    if (ActiveInterval >= EventPtr->RemainingInterval) {

      // Yes, reset the VSM's remaining interval
      EventPtr->RemainingInterval = EventPtr->Interval;

      // Fill message packet      
      MsgPacket[1] = EventPtr->Interval;
      MsgPacket[2] = EventPtr->Handle;

      // Was timer due to a SYS_YIELD ?
      if (EventPtr->Param2 & SYS_YIELD) {
        // Yes, schedule the slumbering VSM
        Schedule_VSM(Vsm);
      }

      // Return its Events[] index
      ReturnValue = EventIndex;
    } else {
      // Decrement RemainingInterval by the expired timer interval
      EventPtr->RemainingInterval -= ActiveInterval;
    }

    // Find the next interval on the current h/w timer to expire
    if (EventPtr->RemainingInterval < Events[NextToExpire].RemainingInterval) {
      // Ignore one-shots that just expired
      if (ReturnValue != EventIndex || !(EventPtr->Param2 & ONE_SHOT)) {
        NextToExpire = EventIndex;
      }
    }
  }

  // If no more timers, then set timer h/w to next interval
  if (!EventPtr->Link) {
    // Set the timer h/w to the next interval to expire
    if (Events[NextToExpire].Vsm) {
      Enable_Event(EVENT_TIMER, NextToExpire, 2);
    }
  }

  return ReturnValue;
}





//***********************************************************************
// This routine decrements all software timers.  If a software timer has
// expired, it sends an event message to the VSM.   The time to the next
// scheduled event and invokes Enable_Event() to restart the timer.
//
//***********************************************************************
void pascal Timer_Handler(USHORT TimerNumber)
{
  // Record the active timer
  ActiveTimer = TimerNumber;
  ActiveInterval = TimerInfo[ActiveTimer].Interval;

  // Mark this timer as available
  MarkTimerAvailable(TimerNumber);

  // Send the timer event
  Send_Event(EVENT_TIMER, 0x00000000);
}



//*****************************************************************************
// Enables a millisecond timer to the specified interval
//
// EnableFlag
//   0 = disable
//   1 = new registration
//   2 = reprogram timer to new interval
//*****************************************************************************
void MillisecondTimer(UCHAR EnableFlag, EVENT_ENTRY * EventPtr)
{
  if (EnableFlag == 0) {

    // Disable the h/w timer
    DisableTimer(EventPtr->Timer);

  } else {

    // Program a hardware timer
    EventPtr->Timer = (UCHAR)EnableTimer(EventPtr->RemainingInterval, EventPtr->Attr);
    
  }
}


