#ifndef EXEC_EXECBASE_H
#include <exec/execbase.h>
#endif

#ifndef EXEC_ALERTS_H
#include <exec/alerts.h>
#endif

#ifndef RESOURCES_MISC_H
#include <resources/misc.h>
#endif

#ifndef HARDWARE_CIA_H
#include <hardware/cia.h>
#endif

#ifndef DOS_FILEHANDLER_H
#include <dos/filehandler.h>
#endif

#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#endif

#ifndef CLIB_DOS_PROTOS_H
#include <clib/dos_protos.h>
#endif

#ifndef CLIB_MISC_PROTOS_H
#include <clib/misc_protos.h>
#endif

#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/misc_pragmas.h>

/***********************************************/

struct Interrupt *CIAA_AddICRVector(long, struct Interrupt *);
void CIAA_RemICRVector(long, struct Interrupt *);
WORD CIAA_AbleICR(long);
WORD CIAA_SetICR(long);

#pragma libcall CIAABase CIAA_AddICRVector 6 9002
#pragma libcall CIAABase CIAA_RemICRVector C 9002
#pragma libcall CIAABase CIAA_AbleICR 12 001
#pragma libcall CIAABase CIAA_SetICR 18 001

extern struct CIA volatile __far ciaa;
extern struct CIA volatile __far ciab;

/***********************************************/

void DummyInterrupt(void) {}   /* Just in case... */

/***********************************************/

void __saveds FastPAR(void)

{
   struct ExecBase *SysBase;
   struct DosLibrary *DOSBase;
   struct DosPacket *Packet;
   struct DeviceNode *DeviceNode;
   APTR MiscBase;
   APTR CIAABase;
   struct Process *MyProcess;
   struct Interrupt CIAAInterrupt;
   WORD OldMask;

   SysBase=(struct ExecBase *)*(ULONG *)4;
   if (!(DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37L)))
      {
         Alert(AT_DeadEnd | AG_OpenLib | AO_DOSLib);
      }
   MyProcess=(struct Process *)(SysBase->ThisTask);

   Packet=WaitPkt();
   DeviceNode=BADDR(Packet->dp_Arg3);
   DeviceNode->dn_Task=&MyProcess->pr_MsgPort;
   ReplyPkt(Packet,DOSTRUE,0L);

   MiscBase=NULL;
   CIAAInterrupt.is_Node.ln_Type=NT_UNKNOWN;
   CIAAInterrupt.is_Node.ln_Name="FastPAR";
   CIAAInterrupt.is_Code=DummyInterrupt;
   while (TRUE)
      {
         Packet=WaitPkt();
         switch(Packet->dp_Type)
            {
               case ACTION_FINDINPUT:
               case ACTION_FINDOUTPUT:
               case ACTION_FINDUPDATE:      if (MiscBase)
                                               {
                                                  ReplyPkt(Packet,DOSFALSE,ERROR_OBJECT_IN_USE);
                                                  break;
                                               }
                                            if (!(MiscBase=OpenResource("misc.resource")))
                                               {
                                                  Alert(AT_DeadEnd | AG_OpenRes | AO_MiscRsrc);
                                               }
                                            if (AllocMiscResource(MR_PARALLELPORT,"FastPAR"))
                                               {
                                                  MiscBase=NULL;
                                                  ReplyPkt(Packet,DOSFALSE,ERROR_OBJECT_IN_USE);
                                                  break;
                                               }
                                            if (AllocMiscResource(MR_PARALLELBITS,"FastPAR"))
                                               {
                                                  FreeMiscResource(MR_PARALLELPORT);
                                                  MiscBase=NULL;
                                                  ReplyPkt(Packet,DOSFALSE,ERROR_OBJECT_IN_USE);
                                                  break;
                                               }
                                            if (!(CIAABase=OpenResource("ciaa.resource")))
                                               {
                                                  Alert(AT_DeadEnd | AG_OpenRes | AO_CIARsrc);
                                               }
                                            Disable();
                                            if (CIAA_AddICRVector(CIAICRB_FLG,&CIAAInterrupt))
                                               {
                                                  Enable();
                                                  MiscBase=NULL;
                                                  ReplyPkt(Packet,DOSFALSE,ERROR_OBJECT_IN_USE);
                                                  break;
                                               }
                                            CIAA_SetICR(CIAICRF_FLG);
                                            OldMask=CIAA_AbleICR(CIAICRF_FLG) & CIAICRF_FLG;
                                            Enable();
                                            ciaa.ciaddrb=0xff;
                                            ciab.ciaddra&=~(CIAF_PRTRSEL | CIAF_PRTRPOUT | CIAF_PRTRBUSY);
                                            ReplyPkt(Packet,DOSTRUE,0L);
                                            break;

               case ACTION_WRITE:           {
                                               long Count;
                                               char *CharPointer;
                                               BYTE OldTaskPri;

                                               CharPointer=(char *)Packet->dp_Arg2;
                                               OldTaskPri=SetTaskPri(MyProcess,-5);
                                               for (Count=0; Count<Packet->dp_Arg3; Count++)
                                                  {
                                                     while (ciab.ciapra & CIAF_PRTRBUSY) ;
                                                     ciaa.ciaprb=*CharPointer++;
                                                     while (!(CIAA_SetICR(CIAICRF_FLG) & CIAICRF_FLG)) ;
                                                  }
                                               SetTaskPri(MyProcess,OldTaskPri);
                                               ReplyPkt(Packet,Count,0L);
                                            }
                                            break;

               case ACTION_END:             CIAA_SetICR(CIAICRF_SETCLR | OldMask);
                                            CIAA_AbleICR(CIAICRF_SETCLR | OldMask);
                                            CIAA_RemICRVector(CIAICRB_FLG,&CIAAInterrupt);
                                            FreeMiscResource(MR_PARALLELBITS);
                                            FreeMiscResource(MR_PARALLELPORT);
                                            MiscBase=NULL;
                                            ReplyPkt(Packet,DOSTRUE,0L);
                                            break;

               case ACTION_DIE:             if (!MiscBase)
                                               {
                                                  Forbid();
                                                  if (IsMsgPortEmpty(&MyProcess->pr_MsgPort))
                                                     {
                                                        ReplyPkt(Packet,DOSTRUE,0L);
                                                        UnLoadSeg(DeviceNode->dn_SegList);
                                                        DeviceNode->dn_SegList=NULL;
                                                        DeviceNode->dn_Task=NULL;
                                                        CloseLibrary((struct Library *)DOSBase);
                                                        return;
                                                     }
                                                  Permit();
                                               }
                                            ReplyPkt(Packet,DOSFALSE,ERROR_OBJECT_IN_USE);
                                            break;

               default:                     ReplyPkt(Packet,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
                                            break;
            }
      }
}
