struct TimerData *SubmitTimer(struct TimerSetupData *TSD, ULONG Seconds,ULONG MicroSeconds )
{
  struct TimerData *TD=NULL;

  if (TD=(struct TimerData*)AllocVec(sizeof(struct TimerData),MEMF_PUBLIC))
  {
    // copy fields accross from our blank timer IO request
    // that was initialised by InitTimer();

    //      Source             Dest   Size
    CopyMem(TSD->BlankTimerIO,&TD->TR,sizeof(struct timerequest));

    TD->TR.tr_time.tv_secs   = Seconds;
    TD->TR.tr_time.tv_micro   = MicroSeconds;
    AddHead(TSD->TimerList,(struct Node*)TD);

    SendIO((struct IORequest *)&TD->TR);
  }
  return(TD);
}

void AbortTimer(struct TimerSetupData *TSD, struct TimerData *CTD)
{
  struct TimerData *TD=NULL;

  for (TD = (struct TimerData *)TSD->TimerList->lh_Head ; TD->node.ln_Succ ; TD =(struct TimerData *) TD->node.ln_Succ)
  {
    if (TD==CTD)
    {
      AbortIO((struct IORequest *)&TD->TR);
      WaitIO((struct IORequest *)&TD->TR);
      FreeVec(TD);
      // TD is now null so we dont wat to reference it again so return from the func..
      return;
    }
  }
}

BOOL CheckTimer(struct TimerSetupData *TSD, struct TimerData *CTD)
{
  struct TimerData *TD=NULL;

  for (TD = (struct TimerData *)TSD->TimerList->lh_Head ; TD->node.ln_Succ ; TD =(struct TimerData *) TD->node.ln_Succ)
  {
    if (TD==CTD)
    {
      if (CheckIO((struct IORequest *)&TD->TR))
      {
        Remove((struct Node*)TD);
        FreeVec(TD);
        return(TRUE);
      }
    }
  }
  return(FALSE);
}

void CleanupTimer( struct TimerSetupData *TSD )
{
  if (TSD)
  {
    if (TSD->TP)
    {
      if (TSD->BlankTimerIO)
      {
        if (TSD->TimerOpen)
        {
          if (TSD->TimerList)
          {
            // remove all outstanding io requests..
            for (TD = (struct TimerData *)TSD->TimerList->lh_Head ; TD->node.ln_Succ ; TD =(struct TimerData *) TD->node.ln_Succ)
            {
              AbortIO((struct IORequest *)&TD->TR);
              WaitIO((struct IORequest *)&TD->TR);
              FreeVec(TD);
              }
            }
            FreeVec(TSD->TimerList);
          }
          CloseDevice((struct IORequest *) TSD->BlankTimerIO);
          TSD->TimerOpen=FALSE;
        }
        DeleteExtIO((struct IORequest *) TSD->BlankTimerIO);
      }
      DeleteMsgPort(TSD->TP);
    }
    FreeVec(TSD);
  }
}

struct TimerSetupData *InitTimer( void )
{
  struct TimerSetupData *TSD;

  if (TSD=AllocVec(sizeof(struct TimerSetupData),MEMF_PUBLIC))
  {
    TSD->TimerOpen=FALSE;
    if (TSD->TimerPort = CreateMsgPort())
    {
      if (TSD->BlankTimerIO = (struct timerequest *) CreateExtIO(TSD->TimerPort,sizeof(struct timerequest)) )
      {
        if (OpenDevice( TIMERNAME, UNIT_VBLANK,(struct IORequest *) TSD->BlankTimerIO, 0L)==0) // success ?
        {
          TSD->TimerOpen=TRUE;
          TSD->BlankTimerIO->tr_node.io_Command = TR_ADDREQUEST;
          if (TSD->TimerList=AllocVec(sizeof(struct List),MEMF_PUBLIC))
          {
            NewList((struct List *)TSD);
            return(TSD);
          }
        }
      }
    }
    CleanupTimer(TSD);
  }
  return(NULL);
}
