/*********************************************************/ /* */ /* 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 */