


/*********************************************************/
/*                                                       */
/* Copyright (c) 1989, David Kinzer, All Rights Reserved */
/*                                                       */
/* Permission hereby granted to redistribute this        */
/* program in unmodified form in a not for profit manner.*/
/*                                                       */
/* Permission hereby granted to use this software freely */
/* in programs, commercial or not.                       */
/*                                                       */
/*********************************************************/
/*                                                       */
/* JoyDriv.c                                             */
/*                                                       */
/* Analog joystick interface routines                    */
/*                                                       */
/* This file contains the routines needed to interface   */
/* to an analog joystick.  The routines supplied will    */
/* open, read, and close an analog joystick port.        */
/* Note that in order to use joyport 0 (left mouse port) */
/* the intuition interface will have to be turned off.   */
/*                                                       */
/*********************************************************/

#include "exec/types.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "hardware/custom.h"
#include "hardware/intbits.h"

#include "ajoystick.h"

#define POTBITS0        0x0F01
#define POTBITS1        0xF001
#define INPUT0          0x0000
#define INPUT1          0x0000
#define INMASK0         0x0A00
#define INMASK1         0xA000




struct joydata {
   struct {
      unsigned short x;
      unsigned short y;
      char b1;
      char b2;
      char b3;
      char b4;
      char eb1;
      char eb2;
      char eb3;
      char eb4;
   } unit0,unit1;
   APTR pgbase;
   long unitflags;
};




APTR PotgoBase = 0;               /* Library base        */
long gotpotgo = 0;                /* Potgo register bits */
                                  /*  we are using       */
struct joydata *JoyData = NULL;   /* Pointer to data     */
                                  /*  passing area       */
struct Interrupt *VBRData = NULL; /* Pointer to VERTB    */
                                  /*  interrupt node     */
extern VOID vbserver();


/* Open Analog Joystick Routine */

struct joydata *OpenAJoystick(units)
long units;
{
long wantpotgo, AllocPotBits();
long inputbits, inputmask;
APTR OpenResource(), AllocMem();


   /* reject open if already opened. */

   if (JoyData) {
      return NULL;
   }

   /* Open potgo resource.  The resource controls        */
   /* allocation and writing of the potgo register.      */
   /* Note: There is no corresponding CloseResource call */
   /*       in the Amiga.                                */

   PotgoBase = OpenResource((STRPTR)"potgo.resource");
   if (!PotgoBase) {
      return NULL;    /* Return error if potgo.resource */
                      /* is not available.              */
   }

   /* figure out which bits we need */

   wantpotgo = 0;
   inputbits = 0;
   inputmask = 0;

   if (units & AJOYUNIT0) {
      wantpotgo |= POTBITS0;
      inputbits |= INPUT0;
      inputmask |= INMASK0;
   }

   if (units & AJOYUNIT1) {
      wantpotgo |= POTBITS1;
      inputbits |= INPUT1;
      inputmask |= INMASK1;
   }

   /* Do we want anything?  If not, return error, since */
   /* there is probably an error in the call.           */

   if (!wantpotgo) {
      return NULL;
   }


   /* Allocate the bits that we need from the potgo  */
   /* resource.                                      */

   gotpotgo = AllocPotBits(wantpotgo);

   /* See if we got what we needed. If not, return error */

   if (wantpotgo != gotpotgo) {
      FreePotBits(gotpotgo); /* give back allocated bits */
      return NULL;
   }


   /* Since we don't know what the hardware was set to   */
   /* before we got it, we shall set the analog joystick */
   /* bits to inputs like we want.                       */

   WritePotgo(inputbits,inputmask);

   /* Now that we have the hardware, we shall set up our */
   /* VERTB (vertical blanking) interrupt server routine.*/
   /* We get some Public memory for a shared data area   */
   /* between the server and the ReadAJoystick routine.  */
   /* Then we set up an interrupt structure which allows */
   /* our server to become a part of the Amiga operating */
   /* system.                                            */

   JoyData = (struct joydata *)AllocMem((long)sizeof
               (struct joydata),MEMF_PUBLIC);
   if (!JoyData) {       /* error if we can't get memory */
      FreePotBits(gotpotgo); /* give back allocated bits */
      return NULL;
   }

   JoyData->pgbase = PotgoBase;     /* send potgobase to */
                                    /*  vertb server     */
   JoyData->unitflags = units;      /* send units to     */
                                    /*  vertb server     */

   JoyData->unit0.x = 0x8000;       /* fill in some      */
   JoyData->unit0.y = 0x8000;       /*  dummy values     */
   JoyData->unit0.b1 = 0;
   JoyData->unit0.b2 = 0;
   JoyData->unit0.b3 = 0;
   JoyData->unit0.b4 = 0;
   JoyData->unit0.eb1 = 0;
   JoyData->unit0.eb2 = 0;
   JoyData->unit0.eb3 = 0;
   JoyData->unit0.eb4 = 0;
   JoyData->unit1.x = 0x8000;       
   JoyData->unit1.y = 0x8000;
   JoyData->unit1.b1 = 0;
   JoyData->unit1.b2 = 0;
   JoyData->unit1.b3 = 0;
   JoyData->unit1.b4 = 0;
   JoyData->unit1.eb1 = 0;
   JoyData->unit1.eb2 = 0;
   JoyData->unit1.eb3 = 0;
   JoyData->unit1.eb4 = 0;

   VBRData = (struct Interrupt *)AllocMem((long)sizeof
                (struct Interrupt),MEMF_PUBLIC);
   if (!VBRData) {       /* error if we can't get memory */
      /* give back memory and allocated potgo bits */
      FreeMem(JoyData,(long)sizeof(struct joydata));
      FreePotBits(gotpotgo);        
      return NULL;
   }


   /* Fill in the blanks of the Interrupt structure */

   VBRData->is_Node.ln_Type = NT_INTERRUPT;
   VBRData->is_Node.ln_Pri = 10;
   VBRData->is_Node.ln_Name = "VERTB for Analog Joystick";
   VBRData->is_Data = (APTR)JoyData;
   VBRData->is_Code = vbserver;

   /* And, finally, add interrupt routine to Operating  */
   /* System.                                           */

   AddIntServer(INTB_VERTB,VBRData);

   /* Return pointer to data, in case user wants to go  */
   /* directly to the data structures.                  */

   return JoyData;

}


/* Close Analog Joystick routine.                       */
/* Note: Since the Units are closely intertwined, I     */
/*       decided to close all open units with one call. */
/*       (since you had to open them with one call      */
/*       anyway).                                       */

long CloseAJoystick()
{

   /* Are we actually open? Error if not */

   if (!JoyData) {
      return 0;
   }

   /* Shut off VERTB routine */

   RemIntServer(INTB_VERTB,VBRData);

   /* Free up memory */

   FreeMem(JoyData,(long)sizeof(struct joydata));  
   FreeMem(VBRData,(long)sizeof(struct Interrupt)); 

   /* Give back allocated potgo bits */

   FreePotBits(gotpotgo);

   /* Set Flag so we don't read bad data */

   JoyData = NULL;

   /* return success */

   return 1;
}


/* Joystick Read routine                                 */
/* Note: Reads values left by last VERTB interrupt.      */
/* Note: Data is stale until first interrupt comes along.*/
/* Note: Only one Unit can be read at a time.            */

struct AJoyData *ReadAJoystick(unit,UserDataPtr)
long unit;
struct AJoyData *UserDataPtr;
{

   /* Are we open? Error if not. */

   if (!JoyData) {
      return NULL;
   }

   /* Is this unit open? Error if not */

   if (!(JoyData->unitflags & unit)) {
      return NULL;
   }

   /* Get data for unit and place in requestor's data    */
   /* structure. (Should be public memory.)              */

   if (unit == AJOYUNIT0) {

      UserDataPtr->x = JoyData->unit0.x;
      UserDataPtr->y = JoyData->unit0.y;

      if (JoyData->unitflags & U0B1SINGLE) {
         UserDataPtr->button1 = JoyData->unit0.eb1;
         JoyData->unit0.eb1 = 0;
      } else 
         UserDataPtr->button1 = JoyData->unit0.b1;

      if (JoyData->unitflags & U0B2SINGLE) {
         UserDataPtr->button2 = JoyData->unit0.eb2;
         JoyData->unit0.eb2 = 0;
      } else 
         UserDataPtr->button2 = JoyData->unit0.b2;

      if (JoyData->unitflags & U0B3SINGLE) {
         UserDataPtr->button3 = JoyData->unit0.eb3;
         JoyData->unit0.eb3 = 0;
      } else 
         UserDataPtr->button3 = JoyData->unit0.b3;

      if (JoyData->unitflags & U0B4SINGLE) {
         UserDataPtr->button4 = JoyData->unit0.eb4;
         JoyData->unit0.eb4 = 0;
      } else 
         UserDataPtr->button4 = JoyData->unit0.b4;

   } else if (unit == AJOYUNIT1) {

      UserDataPtr->x = JoyData->unit1.x;
      UserDataPtr->y = JoyData->unit1.y;

      if (JoyData->unitflags & U1B1SINGLE) {
         UserDataPtr->button1 = JoyData->unit1.eb1;
         JoyData->unit1.eb1 = 0;
      } else 
         UserDataPtr->button1 = JoyData->unit1.b1;

      if (JoyData->unitflags & U1B2SINGLE) {
         UserDataPtr->button2 = JoyData->unit1.eb2;
         JoyData->unit1.eb2 = 0;
      } else 
         UserDataPtr->button2 = JoyData->unit1.b2;

      if (JoyData->unitflags & U1B3SINGLE) {
         UserDataPtr->button3 = JoyData->unit1.eb3;
         JoyData->unit1.eb3 = 0;
      } else 
         UserDataPtr->button3 = JoyData->unit1.b3;

      if (JoyData->unitflags & U1B4SINGLE) {
         UserDataPtr->button4 = JoyData->unit1.eb4;
         JoyData->unit1.eb4 = 0;
      } else 
         UserDataPtr->button4 = JoyData->unit1.b4;

   } else return NULL;  /* Error, not a recognised unit */

   /* return success */

   return UserDataPtr;

}

/* End: JoyDriv.c */
