/*
 * Timer.device routines from RKM, slightly modified.
 *
 * Version 1.88:  Renamed routine TimeDelay() to MyDelay(), since the former
 * conflicts with a routine of the same name in the 2.0 amiga.lib.
 *
 * Version 1.90:  Created a GetSysTime() routine.  Made sure that if
 * the CreateExtIO() in CreateTimer() fails, the timerport is deleted.
 */

#ifndef _lint
static char rcsid[] = "$Header$";
#endif

#include "ckxtim.h"

void
DeleteTimer(struct timerequest *tr) {
   struct MsgPort *tp;

   if (tr != 0) {
      tp = tr->tr_node.io_Message.mn_ReplyPort;
      if (tp != 0)
         DeletePort(tp);
      CloseDevice((struct IORequest *) tr);
      DeleteExtIO((struct IORequest *) tr);
   }
}

struct timerequest *
CreateTimer(ULONG unit) {
   /* return a pointer to a timer request.  If any problem, return NULL. */

   LONG error;
   struct MsgPort *timerport;
   struct timerequest *timermsg;
   
   timerport = CreatePort(0, 0);
   if (timerport == NULL)
      return NULL;
   timermsg = (struct timerequest *)
              CreateExtIO(timerport, sizeof(struct timerequest));
   if (timermsg == NULL) {
      DeletePort(timerport);
      return NULL;
   }
   error = OpenDevice((UBYTE *) TIMERNAME, unit,
                      (struct IORequest *) timermsg, 0L);
   if (error != 0) {
      DeleteTimer(timermsg);
      return NULL;
   }
   return timermsg;
}

void
WaitForTimer(struct timerequest *tr, struct timeval *tv) {
   /*----------------------------------------------*/
   /* With the UNIT_MICROHZ timer, it is illegal   */
   /* to wait for 0 or 1 microseconds!             */
   /*----------------------------------------------*/
   if (tv->tv_secs == 0L && tv->tv_micro < 2L) return;
   
   tr->tr_node.io_Command = TR_ADDREQUEST;	/* add a new timer request */

   /* Post request to the timer--will go to sleep till done. */
   DoIO((struct IORequest *) tr);
}

/* More precise timer than AmigaDOS Delay() */

LONG MyDelay(struct timeval *tv, LONG unit) {
   struct timerequest *tr;
   
   tr = CreateTimer(unit);
   if (tr == NULL) return -1L;
   WaitForTimer(tr, tv);
   DeleteTimer(tr);
   return 0L;
}

void
GetSysTime(struct timeval *tv) {
   struct timerequest *tr;

   if ((tr = CreateTimer(UNIT_MICROHZ)) == NULL)
      return;
   tr->tr_node.io_Command = TR_GETSYSTIME;
   DoIO((struct IORequest *) tr);
   *tv = tr->tr_time;
   DeleteTimer(tr);
}
