
/*
 *   Wedge.c
 *   by Bart Whitebook
 *
 * Copyright (c) 1988 Commodore-Amiga, Inc.
 *
 * Executables based on this information may be used in software
 * for Commodore Amiga computers.  All other rights reserved.
 *
 * This information is provided "as is"; no warranties are made.
 * All use is at your own risk, and no liability or responsibility is assumed.
*/

/*  This code was created under Greenhills.
 *  It compiles under Manx with the cflags:
 *
 *   +L +C +D +p -B -S -L100
 */

/******************************************************************************
*
*   Source Control
*   --------------
*   $Header: wedge.c,v 35.8 88/03/23 09:51:24 bart Exp $
*
*   $Locker:  $
*
*   $Log:   wedge.c,v $
*   Revision 35.8  88/03/23  09:51:24  bart
*   remove() mods
*   
*   Revision 35.7  88/03/22  18:55:42  bart
*   if(wp) in dispose
*   
*   Revision 35.6  88/03/22  15:17:24  bart
*   keep opencount
*   
*   Revision 35.0  88/03/01  11:20:28  bart
*   added to rcs for updating
*   
*
******************************************************************************/


#include <exec/types.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>

#ifdef DEBUG
#define KPRINTF
#endif

#ifdef KPRINTF
#define printf kprintf
#endif

#define JSR_ABS   0x4EB9
#define JSR_dPC   0x4EBA

#define JMP_ABS   0x4EF9
#define JMP_dPC   0x4EFA

#define   RTS      0x4E75

struct Wedge {
   UWORD   wedge_Vectors[20];
   struct    Library   wedge_Library;
   WORD   wedge_Offset;
} ;

/* support code for usecount */

#define MOVEM_REG_SP 0x48E7
#define REG_TO_MEM   0x0080
#define LEA_dPC        0x41FA
#define ADDQ_1        0x5250
#define SUBQ_1        0x5350
#define NO_OP       0x4E71
#define MOVEM_SP_REG 0x4CDF
#define MEM_TO_REG   0x0100

new_wedge()
{
   struct Wedge *wp = NULL;

   /* allocate a wedge */

   if(wp=(struct Wedge *)AllocMem(sizeof(struct Wedge),MEMF_PUBLIC|MEMF_CLEAR))
   {
      /* initialize the wedge library to default values */

      wp->wedge_Library.lib_Node.ln_Type = NT_LIBRARY;
      wp->wedge_Library.lib_NegSize = 12;
      wp->wedge_Library.lib_PosSize = sizeof(struct Library)+sizeof(WORD);
      wp->wedge_Library.lib_Version = 35;
      wp->wedge_Library.lib_Revision = 1;

      /* initialize the wedge vectors to default values */

      wp->wedge_Vectors[0]  = MOVEM_REG_SP;   /* increment opencount */
      wp->wedge_Vectors[1]  = REG_TO_MEM;
      wp->wedge_Vectors[2]  = LEA_dPC;
      wp->wedge_Vectors[3]  = 0x0042;
      wp->wedge_Vectors[4]  = ADDQ_1;
      wp->wedge_Vectors[5]  = MOVEM_SP_REG;
      wp->wedge_Vectors[6]  = MEM_TO_REG;

      wp->wedge_Vectors[7]  = JSR_dPC;      /* do wedge function */
      wp->wedge_Vectors[8]  = 0x0004;          /* default */
      wp->wedge_Vectors[9]  = RTS;         /* return */

      wp->wedge_Vectors[10] = MOVEM_REG_SP;   /* decrement opencount */
      wp->wedge_Vectors[11] = REG_TO_MEM;
      wp->wedge_Vectors[12] = LEA_dPC;
      wp->wedge_Vectors[13] = 0x002E;
      wp->wedge_Vectors[14] = SUBQ_1;
      wp->wedge_Vectors[15] = MOVEM_SP_REG;
      wp->wedge_Vectors[16] = MEM_TO_REG;

      wp->wedge_Vectors[17] = JMP_dPC;        /* do old function */
      wp->wedge_Vectors[18] = 0x0002;         /* default */
      wp->wedge_Vectors[19] = RTS;          /* return */
   }

   return((ULONG)wp);
}

dispose_wedge(wp)
struct Wedge *wp;
{
   /* to be strict, we must assume that some task's pc is */
   /* about to execute this wedge: so we must leave the wedge */
   /* in memory until the opencount of this wedge is 0 before */
   /* we are free to delink the wedge "function"... not that the */
   /* wedge structure itself must remain in memory when we are gone */

   if(wp)
   {
      Forbid();

      while(wp->wedge_Library.lib_OpenCnt != 0) WaitTOF();

      Disable();

      wp->wedge_Vectors[7] = JSR_dPC;  /* install default function */
      wp->wedge_Vectors[8] = 0x0004;   /* in place of wedge function */
      wp->wedge_Vectors[9] = RTS;       /* and return */

      Enable();

      Permit();
   }
}

test_wedge(wp)
struct Wedge *wp;
{
   ULONG is_wedge = NULL;
   UBYTE *pred;

   /* make certain that wp is not odd -- it will be if wp == default vector */

   if(((ULONG)wp)^1)
   {
      if(wp->wedge_Library.lib_Node.ln_Type == NT_LIBRARY)
      {
         if(pred = wp->wedge_Library.lib_Node.ln_Pred)
         {
            if(((ULONG)pred)^1)
            {
               if(wp==(struct Wedge *)*(ULONG *)(pred+wp->wedge_Offset+2))
               {
                  is_wedge = (ULONG)wp;
               }
            }
         }
      }
   }
   return(is_wedge);
}

link_wedge(lib,offset,wedge)
UBYTE *lib;
WORD offset;
struct Wedge *wedge;
{
   ULONG is_wedge = NULL;
   struct Wedge *owp;
   UBYTE *pred;

   if(owp = (struct Wedge *)test_wedge(*(ULONG *)(lib+offset+2)))
   {
      is_wedge = (ULONG)owp;
      owp->wedge_Library.lib_Node.ln_Pred = wedge;
      owp->wedge_Offset = -6;
   }
   return(is_wedge);
}

delink_wedge(lib,offset,wp)
UBYTE *lib;
WORD offset;
struct Wedge *wp;
{
   struct Wedge *owp = NULL;
   struct Wedge *nwp;

   if(wp)
   {
      /* prevent unpleasant suprises */

      Disable();

      /* is this still a valid wedge? */

      if(owp = (struct Wedge *)test_wedge(wp))
      {
         struct Library *pred = owp->wedge_Library.lib_Node.ln_Pred;

         /* yes, valid. does this wedge point to another wedge? */

         if( nwp = (struct Wedge *)
               test_wedge(*(ULONG *)(&owp->wedge_Vectors[18]))
           )
         {
            nwp->wedge_Library.lib_Node.ln_Pred = pred;
         }

         /* does the previous library point to this wedge's library */

         if(pred->lib_Node.ln_Succ == &owp->wedge_Library)
         {
            /* yes, make previous library point to next wedge's library */

            pred->lib_Node.ln_Succ == &nwp->wedge_Library;
         }

         /* make previous vector point to next vector */   

         SetFunction( wp->wedge_Library.lib_Node.ln_Pred,
                   wp->wedge_Offset,
                   *(ULONG *)(&wp->wedge_Vectors[18]));

         /* now the wedge is delinked... */
      }
      else
      {
         /* wedge not validated... */
         /* assume that has been setfunction'ed away, */
         /* and may be setfunction'ed back in the near future: */
         /* install default function, if wedge not in use */

         if(wp->wedge_Library.lib_OpenCnt == 0)
         {
            wp->wedge_Vectors[7] = JSR_dPC; 
            wp->wedge_Vectors[8] = 0x0004;   
            wp->wedge_Vectors[9] = RTS;      
         }
      }

      /* suprises ok now, i guess... */

      Enable();
   }

   return((ULONG)owp);
}

install_wedge(lib,offset,entry)
struct Library *lib;
WORD offset;
ULONG entry;
{
   struct Wedge *wp = NULL;

   if( (entry) && (wp = (struct Wedge *)new_wedge()) )
   {
      /* prevent unpleasant suprises */

      Disable();

      /* point this wedge at our new entry */

      wp->wedge_Vectors[7] = JSR_ABS;
      *(ULONG *)(&wp->wedge_Vectors[8]) = entry;

      /* point this wedge at the previous entry */

      wp->wedge_Library.lib_Node.ln_Pred = lib;
      wp->wedge_Offset = offset;

      /* link this wedge to existing wedge? */

      wp->wedge_Library.lib_Node.ln_Succ = 
         (struct Node *) link_wedge(lib,offset,wp);

      /* install this wedge in place of the old entry */

      wp->wedge_Vectors[17] = JMP_ABS;
      *(ULONG *)(&wp->wedge_Vectors[18]) = SetFunction(lib,offset,wp);

      /* suprises ok now, i guess... */

      Enable();
   }

   return((ULONG)wp);
}

remove_wedge(wedge)
struct Wedge *wedge;
{
   delink_wedge(wedge);
   dispose_wedge(wedge);
}

