/*
    intel8254.c, Copyright  (c) by Matthias Gries,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public Licence.
 
    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
 
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/IO/mips/Drivers/intel8254.c,v $
 	Author(s):             Matthias Gries
 	Affiliation:           ETH Zuerich, TIK
 	Version:               $Revision: 2922 $
 	Creation Date:         
 	Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $      by: $Author: baderma $
	
	
*/

/* uncomment the next line to enable the timer interrupt handler */
/* #define TIMER_INTERRUPT_HANDLER_ON */

#include "Drivers/intel8254.h"
#include "Messages.h"
#include "IODevice.h"
#include "Syscall.h"

typedef struct
{
  ThreadId callerid; /* ThreadId of calling thread */
  ThreadId timerid;  /* ThreadId of Timer-driver thread */
}
timer_temp;

#ifdef TIMER_1
IODeviceDesc intel8254Desc = {
                               NULL, NULL,           /* pointers for doubly linked list */
                               "timer1",             /* device name */
                               (Address)COUNTER1,    /* device base address */
                               NULL,                 /* no buffer needed */
                               CLOCKINT_1,           /* interrupt */
                               .....,                /* count down timer interrupt handler */
                               0,                    /* thread id filled in after start */
                               .....,                /* device read function */
                               .....,                /* device write function */
                               .....,                /* device close function */
                               .....,                /* device init function */
                               .....,                /* private msg handler */
                               FALSE,                /* initialisation state, normally FALSE */
                               NULL                  /* data extension */
                             };
#endif

void timer1_interruptHandler(IODevice this)
{
  /* Stop the clock (reset). If not done the interrupt is generated once again and again ... */
  tmResetClockInterrupt(CLOCK1);
  /* this is nolonger done in "intDispatcher()" in TMHal.c */

  /* ioConsolePutString("interrupt handler timer1\n"); */

  if (this->extension != NULL) /* timer has been started using msg handler */
  {
#ifdef TIMER_INTERRUPT_HANDLER_ON
    Message sendmsg;

    sendmsg.from =                 ;
    sendmsg.id   =                 ;

    if ( kSend(                       ,               ) != TM_OK )
      PANIC("timer interrupt handler unable to send message");

    hmFree(                            );
    this->extension = NULL;

    /* count-down finished, no further interrupts */
#endif

  }
}


Error timer1_init(IODevice this)
{
  /* ioConsolePutString("timer init\n"); */

  if (this->isInitialised == FALSE)
  {
    this->isInitialised = TRUE;
    this->extension = NULL; /* just to be sure */
  }
  return IO_INITOK;
}


Error timer1_stop(IODevice this)
{
  /* ioConsolePutString("timer stop\n"); */

  if (this->isInitialised)
    this->isInitialised = FALSE; /* Unset Initialized flag */

  if (this->extension != NULL)
    hmFree((Address) this->extension);
  this->extension = NULL;

  return IO_CLOSEOK;
}


void timer1_messageHandler(IODevice this, Message* msg)
{
  if ((msg->id == IO_TIMER_START) && (msg->msg.ioTimer.period != 0))
  {
    ThreadId dummy;
    /* ioConsolePutString("timer message handler : start message received\n"); */

    if ((msg->msg.ioTimer.period > 0) && (msg->msg.ioTimer.period <= 1750))
    {
      if (setClockValue(CLOCK1, msg->msg.ioTimer.period, SWTRIGGER) != TM_OK)
        PANIC("timer1 could not be properly configured");
    }
    else
    {
      ioConsolePutString("period not within timer range (1 to 1750 [ms]) \n");
      return;
    }

    if (HM_ALLOCFAILED == hmAlloc((Address*) &(this->extension), sizeof(timer_temp)))
      PANIC("no heap space left in timer1_messageHandler");
    else
      ((timer_temp*)(this->extension))->callerid = msg->from; /* used in msg interrupt handler */

    if (tmGetInfo(SELF, &(((timer_temp*)(this->extension))->timerid), &dummy) != TM_INFOOK)
      /* get own ThreadId */
      ioConsolePutString("tmGetInfo failed in timer1-msghandler\n");
  }

  else
    ioConsolePutString("WARNING: message not understood by timer1 message handler\n");
}
