/*----------------------------------------------------------------------------
   File   :    IHandler.c
   Projekt:    --
   Inhalt :    InitIHandler  (initialisiert Speicher & Devices)
               CloseIHandler (macht alles rückgängig)
               InputHandler (der eigentliche Handler)
               LaunchIHandler (startet den da oben..)
               CatchIHandler (.. und fängt ihn wieder ein)

   Version:    0.12
   Datum  :    18.April 1991

   Autor  :    Uwe Röhm
   Adresse:    Auber Str. 25,  W-6209 Hohenstein 4
    (Semester) Wörthstr. 18    W-8390 Passau
   Bemerkung:
   Support-Routinen zur einfachen Programmierung eines eigenen InputHandlers.
----------------------------------------------------------------------------*/

#include <exec/Types.h>
#include <exec/io.h>
#include <exec/ports.h>
#include <exec/interrupts.h>
#include <devices/input.h>
#include <devices/InputEvent.h>
#include "IHandler.h"

#ifndef LATTICE
   #include <functions.h>
#else
   #include <proto/exec.h>
#endif

/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  InitIHandler
   Parameter :  struct MsgPort* (Zeiger auf einen Port oder NULL, für neuen)
                int IENr (Anzahl der InputEvents, für die ich Platz hole)
                int Time (Zahl der Ticks zwischen den Signals vom Handler)
   Rückgabe  :  struct IHandCom * (Zeiger auf fertige Struktur oder NULL)

   Aufruf von:  -?-
   UnterFunks:  CloseIHandler (s.u.)
   Autor     :  Floyd
   Datum     :  14.03.1991
   Bemerkung:
   Die gemeinsame Datenstruktur des Handlers und des PRGs wird initialisiert.
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
struct IHandCom *InitIHandler (struct MsgPort *PPtr, int IENr, int Time)
{
   struct IHandCom *ret = NULL;

   ret = (struct IHandCom *) AllocMem (sizeof (*ret), IHANDMEMOPT);
   if (ret)
   {
      if (PPtr)
         ret->Port = PPtr;
      else
         ret->Port = (struct MsgPort*) CreatePort (IHANDPORTNAME, 0);

      if (ret->Port)
      {
         ret->InpDev = (struct IOStdReq *) CreateExtIO (ret->Port, sizeof (struct IOStdReq));
         if (ret->InpDev)
         {
            if( OpenDevice ("input.device", NULL,(struct IORequest *) ret->InpDev, NULL) )
            {
               DeleteExtIO ((struct IORequest *) ret->InpDev);
               ret->InpDev = NULL;
            }
            else
            {
               ret->Inter = (struct Interrupt *) AllocMem (sizeof (*ret->Inter), IHANDMEMOPT);
               ret->BufStart = (struct InputEvent*) AllocMem (sizeof (struct InputEvent) * IENr, IHANDMEMOPT);
               if (ret->BufStart && ret->Inter)
               {
                  ret->BufEnde = ret->BufStart + IENr;
                  ret->BufMarke= ret->BufStart;
                  ret->BufWrite= ret->BufStart;
                  ret->SigTask = ret->Port->mp_SigTask;
                  ret->TimerMax= Time;
                  ret->is_launched = FALSE;
                  ret->SigBit  = AllocSignal (-1);
                  if (ret->SigBit != -1)
                      return ret;
               }
            }
         }
      }
   }

   CloseIHandler (ret);
   return NULL;
}


/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  CloseIHandler
   Parameter :  struct IHandCom * (Zeiger auf freizugebende Struktur)
   Rückgabe  :  --

   Aufruf von:  -?-
   UnterFunks:  CatchIHandler (s.u.)
   Autor     :  Floyd
   Datum     :  14.03.1991
   Bemerkung:
   Die gemeinsame Datenstruktur des Handlers und des PRGs wird freigegeben.
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
VOID CloseIHandler (struct IHandCom *ihc)
{
   if (ihc)
   {
      CatchIHandler (ihc);

      if (ihc->InpDev)
      {  DeleteExtIO ((struct IORequest *) ihc->InpDev);
         ihc->InpDev = NULL;
      }

      if (ihc->Port)
         DeletePort (ihc->Port);

      if (ihc->BufStart)
      {  FreeMem (ihc->BufStart, (ihc->BufEnde - ihc->BufStart) * sizeof (struct InputEvent));
         ihc->BufStart = NULL;
      }

      if (ihc->Inter)
      {  FreeMem (ihc->Inter, sizeof (struct Interrupt));
         ihc->Inter = NULL;
      }

      if (ihc->SigBit)
         FreeSignal (ihc->SigBit);

      FreeMem (ihc, sizeof (*ihc));
   }
}


/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  InputHandler
   Parameter :  struct InputEvent *ie1 (Zeiger auf Events...)
                struct IHandCom *ihc (Zeiger auf eigene Datenstruktur...)
   Rückgabe  :  struct InputEvent *(wie genommen, so zeronnen)

   Aufruf von:  InputDevice (im ROM !)
   UnterFunks:  --
   Autor     :  Uwe Röhm
   Datum     :  18.04.1991
   Bemerkung:
   ein kleiner Beispiels-Inputhandler ...
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
struct InputEvent* __regargs InputHandler(struct InputEvent *ie1,struct IHandCom *ihc)
{
struct InputEvent *iez;

   iez = ie1;
   do
   {
      switch (iez->ie_Class)
      {
         case IECLASS_RAWKEY:
         case IECLASS_RAWMOUSE:
            if (ihc->does_control)
            {
               CopyMem (iez, ihc->BufMarke, sizeof (struct InputEvent));
               if (iez->ie_Class == IECLASS_RAWKEY)
                  ihc->BufMarke->ie_Class = IECLASS_GADGETDOWN;
               else
                  ihc->BufMarke->ie_Class = IECLASS_GADGETUP;
               ihc->BufMarke->ie_NextEvent = NULL;
               ihc->BufMarke++;
               if (ihc->BufMarke == ihc->BufEnde)
                  ihc->BufMarke = ihc->BufStart;
            }
            break;
         case IECLASS_TIMER:
            ihc->Timer++;
            if (ihc->Timer > ihc->TimerMax)
            {
               ihc->Timer = 0;
               Signal (ihc->SigTask, (1 << ihc->SigBit));
            }
            break;
         default:
            break;
      }
   }
   while (iez = iez->ie_NextEvent);

   return ie1;
}


/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  LaunchIHandler
   Parameter :  struct IHandCom *ihc (Zeiger auf gemeinsame Struktur)
                BYTE Priority (Priorität des InputHandlers)
                char *Handlername (eben dieser)
   Rückgabe  :  BOOL (TRUE -> gestartet, sonst Fehler: FALSE)

   Aufruf von:  -?-
   UnterFunks:  --
   Autor     :  Floyd
   Datum     :  14.03.91
   Bemerkung:
   startet obrigen InputHandler...
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
BOOL LaunchIHandler (struct IHandCom *ihc, BYTE Priority, char *Handlername)
{
   if (ihc->is_launched)
      return FALSE;
   else
   {  ihc->Inter->is_Code        = (VOID *) InputHandler;
      ihc->Inter->is_Data        = (APTR) ihc;
      ihc->Inter->is_Node.ln_Pri = Priority;
      ihc->Inter->is_Node.ln_Name= Handlername;

      ihc->InpDev->io_Data    = (APTR) ihc->Inter;
      ihc->InpDev->io_Command = IND_ADDHANDLER;
      DoIO ((struct IORequest *) ihc->InpDev);
      ihc->is_launched = TRUE;
   }
   return TRUE;
}


/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  CatchIHandler
   Parameter :  struct IHandCOm *ihc (Zeiger auf .... <gähn>)
   Rückgabe  :  --

   Aufruf von:  -?-
   UnterFunks:  --
   Autor     :  Floyd (ich)
   Datum     :  14.03.1991
   Bemerkung:
   Holt den InputHandler wieder aus dem System...
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
VOID CatchIHandler (struct IHandCom *ihc)
{
   if (ihc->is_launched)
   {
      ihc->InpDev->io_Data    = (APTR) ihc->Inter;
      ihc->InpDev->io_Command = IND_REMHANDLER;
      DoIO ((struct IORequest *) ihc->InpDev);
      ihc->is_launched = FALSE;
   }
}

