                 Emil Gilliam's Guide to Game Port Programming
                               Revised 10/30/93

TABLE OF CONTENTS

Section  Name         

         LEGAL INFORMATION
   0     SUMMARY OF CHANGES FROM 10/22/93 AND 06/10/93 REVISIONS
   1     INTRODUCTION
   2     ROM BIOS GAME PORT FUNCTIONS
   3     ACCESSING THE GAME I/O PORT DIRECTLY
   4     INTERPRETING THE JOYSTICK X AND Y VALUES
   5     GRAVIS GAMEPAD
   6     PADDLES
   7     DETECTING THE GAME PORT AND CONTROLLERS
   8     GAME PORT PINOUTS
   9     HOW TO CONTACT ME

------------------------------------------------------------------------------

LEGAL INFORMATION

   This "Joystick Guide" is (C) Copyright 1993 Emil Gilliam.  All rights 
reserved.

THIS DOCUMENT AND THE ACCOMPANYING SOURCE CODE FILE ARE PROVIDED "AS IS" 
WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  EMIL GILLIAM WILL NOT BE 
HELD LIABLE FOR ANY DAMAGES OR LOSSES OF ANY KIND THAT RESULT FROM THE USE OR 
THE INABILITY TO USE THE INFORMATION PROVIDED IN THIS DOCUMENT OR THIS SOURCE 
CODE FILE, INCLUDING, BUT NOT LIMITED TO, LOSS OF PROPERTY OR INCOME. 

   This document and its accompanying source code file are freeware, not 
public domain.  They may be distributed freely provided that neither file is 
modified, and that they are distributed together along with FILE_ID.DIZ in 
their entirety, including the legal notice, and that: 
   If they are distributed by a computer club, no more than $5 U.S. is charged 
for the disk on which the archive containing this document and the 
accompanying source code file is stored; if they are to be distributed by a 
shareware/freeware company (for example, on a CD-ROM collection of files), my 
permission is obtained first. 
   This legal information supersedes all previous notices.

------------------------------------------------------------------------------

0.0  SUMMARY OF CHANGES FROM 10/22/93 AND 06/10/93 REVISIONS

Changes from 10/22/93 revision:

    Improved copyright notice, thanks to:
        Kip Cooley at the Diamond Bar BBS (909) 923-1031 (1:218/101).
        Ian Remmler at the DownTown BBS (210) 625-4479 (1:387/1001).

    Bug fix (SI and DI should be saved, ES was saved incorrectly in 
        read_2_joysticks) in read_1_joystick and read_2_joysticks.  Thanks to
        Kip Cooley (see above).

    A little optimization in the detect_game_port procedure, thanks to David
        Kirschbaum, "Toad Hall," at the Federal Post BBS (1:3634/2).

    FILE_ID.DIZ file added.

    A big thanks to everyone who has made suggestions for this Guide!

Changes from 06/10/93 revision:

    More specific about precision and ranges of coordinates in section 4.1.
    Added information about game-port bit in equipment-status word.
    More specific about the joystick port itself (in section 8).

------------------------------------------------------------------------------

1.0  INTRODUCTION
        
1.1  About the game port
        
   Any machine in the IBM PC family of computers can have a game port, either 
built-in or on an add-on card.  As suggested by its name, the game port is 
where you can connect one or two joysticks, or other controllers suitable for 
playing games with, to the computer.  This document describes how a program 
accesses the game port, so if you're writing a game or other program that uses 
a joystick or other such controller, you'll know how to get your program to 
get the status of the joystick or whatever is hooked up to the game port. 
   As far as I know, three things can be connected to a game port: an analog 
joystick (you can have up to two connected at once), a Gravis GamePad, which 
is a digital joystick (see section 5), or up to four paddles (see section 6).  
By far, analog joysticks are more commonly used for game controllers than the 
other two.  (I have never actually seen a paddle for the IBM in my life, nor 
seen a program that uses it; I only know that such a thing exists, but it must 
be extremely rare or old.  I only included information on it here for 
completeness.) 
   When analog joysticks are connected to the game port, they are referred to 
as joysticks A and B (for player 1 and player 2 in a game, respectively).  
Each analog joystick has two buttons on it.  The stick itself is opposed to 
the type of joystick on a Gravis GamePad or to what's used for a Nintendo or 
Sega, or to the joysticks used on many early home computers that have 9-pin 
joystick connectors, all of which are "digital" joysticks.  (Usually in this 
document, if I refer to simply the "joystick," I'm talking about the analog 
joystick.) 
        
1.2  The difference between an analog and a digital joystick
        
   What's the difference between an analog joystick and a digital joystick?  
Inside a digital joystick like the Gravis GamePad, there are simple switches 
which can only detect if the joystick is all the way up, down, left, or right, 
at any of the 4 diagonals, or at the center.  The joystick therefore has only 
9 distinct positions.  In an analog joystick, however, the joystick has 
potentiometers inside it that can tell where the stick's position is more 
accurately, so a program doesn't have to know that the joystick is somewhere 
to the left of the center or whatever; it can know just how far it is to the 
left. The joystick gives information to the computer about where the stick's 
coordinates are. 
        
1.3  Reading the controller values

   The game port isn't tied to any interrupts; if you're writing a game or 
some other application that does something whenever a joystick button is 
pressed or whenever the stick is moved (or the paddle is turned), you have to 
program it to "poll" the game port, in other words, read the game port status 
over and over (perhaps many times per second) and see if a button is being 
pressed or the joystick is in a particular position. 
   There are two ways for a program to get the status of the game port (and 
thus of whatever controller is connected to it): It can call the ROM BIOS 
functions to do it (see section 2), or it can directly use the I/O ports that 
are connected to the game port (see section 3). 
      
------------------------------------------------------------------------------

2.0  ROM BIOS JOYSTICK FUNCTIONS

2.1  About the functions
        
   Here are the ROM BIOS functions for reading the joystick positions and 
button status.  (You can also use them for getting the status of the paddles, 
see section 6.)  Beware that some older machines (original PC's and PCjr's, 
and XT's whose BIOSes date back to 11/08/82) don't support these INT 15h 
functions in their ROM BIOSes.  (It's ironic that PCjr's don't support these 
functions, because all PCjr's have a game port - I think.  XT's with newer 
BIOSes, 01/10/86, do support these functions.)  

2.2  Function to get button status
        
INT 15h Function 84h - joystick functions

    Subfunction 0 - get joystick button status
    DON'T USE THIS UNLESS YOU ABSOLUTELY HAVE TO -- IT'S SLOW!!!  See 2.5.
    Call with: AH=84h, DX=0
    Returns:
        On PC's and PCjr's (which don't support this function), AH=80h and 
        CF=1, other flags: undefined
        
        On PC XT's whose BIOSes date to 11/08/82 (which also don't support
            this function, AH=86h and CF=1, other flags undefined

        On all other machines (which do support this function), CF=0,
            AH: Bits 0-3 - undefined (probably 0 but don't count on it)
                Bit  4   - Joystick A button 1 status (1=button not pressed,
                                                       0=button being pressed)
                Bit  5   - Joystick A button 2 status (ditto)
                Bit  6   - Joystick B button 1 status (ditto)
                Bit  7   - Joystick B button 2 status (ditto)
            Note: Those are the bit definitions for the analog joystick.  See
            the sections on the Gravis GamePad (section 5) and the paddles 
            (section 6) for the bit definitions for those controllers.
            DX: Undefined (probably 201h but don't bet your life on it)
            Other flag registers: undefined

            Officially, this function will can return CF=1 if there was an 
            error reading the joystick button values or there is no game 
            adapter.  I don't see how that can ever happen; the ROM BIOS code 
            can't return CF=1 and never checks to see if a game adapter is 
            installed at all, at least in the 01/10/86 XT BIOS. 

2.3  Function to get joystick position
    
INT 15h Function 84h - joystick functions

    Subfunction 1 - get joystick position
    Call with: AH=84h, DX=1
    Returns:
        On PC's, PCjr's, and XT's with 11/08/82 BIOSes (which don't support 
        this function), see section 2.2. 

        On all other machines (which do support this function), CF=0,
            AX = Joystick A x-coordinate (see section 4 about these)
            BX = Joystick A y-coordinate (ditto)
            CX = Joystick B x-coordinate (ditto)
            DX = Joystick B y-coordinate (ditto)
            Note: These are the register definitions for the analog joystick.  
            See the sections on the Gravis GamePad (section 5) and the paddles 
            (section 6) for the register definitions for those controllers.
            Other flag registers: undefined

            Officially, this function can also return CF=1 if there was an 
            error, like no adapter card.  However, at least in the 01/10/86 XT 
            BIOS, this can't ever happen; the code never checks for an adapter 
            card.  Upon exit, any of the four registers for joystick values 
            will be equal to 0 if that joystick isn't connected (or if the 1 
            bit in the game port register for that coordinate never turned 0 
            within a reasonable amount of time; you'd know what the heck I'm 
            talking about if you read section 3.) 

2.4  Advantage to using ROM BIOS functions

   Really, there aren't a whole lot of reasons for using the ROM BIOS 
functions for reading the joystick (or other controller) status.  I suppose if 
you're doing some quick-and-dirty program, it's easier because you don't have 
to come up with the routine yourself.  If there is a joystick emulator of some 
sort installed, it might intercept the joystick calls to interrupt 15h (but it 
would more likely put the processor into V86 mode and trap I/O to port 201h if 
the processor is a 386 or up) and so your program might work with it better.  
This is quite unlikely because I've never seen anything that emulates a 
joystick or other controller. 

2.5  Disadvantages to using the ROM BIOS functions

   The big minus to using the ROM BIOS functions for reading the joystick (or 
other controller) status is that they're really SLOW!  Considering how many 
things have to trap interrupt 15h (DOS, the XMS driver, and probably other 
things), and how the ROM BIOS has to check the function number and do other 
maintenance garbage, like with the CMOS RAM on some newer ROM BIOSes, the 
system wastes a lot of time just getting to the joystick routines.  Also, the 
ROM BIOS routine for reading the joystick position is quite slow because it 
reads the joystick coordinates one at a time instead of all at once (as far as 
I know that's how it's done in all ROM BIOSes).  At least, don't call INT 15h 
for getting the joystick button values if you can help it; you can get the 
joystick button status in just two instructions; I'll even give some code for 
doing that if you are a beginner at assembly language or are too lazy to 
figure this one out.  (See the routine button_status in JOYSTICK.ASM.)
   The other disadvantage is that some older machines (original PC's, PCjr's, 
and XT's whose BIOSes date back to 11/08/82) don't support these INT 15h 
functions in their ROM BIOSes.  (XT's with newer BIOSes, 01/10/86, do support 
these functions.)  On the machines that don't support the joystick functions 
in their ROM BIOSes, in order to read the joystick values or get the status of 
the buttons, you have to do it yourself with hardware ports.  (See section 3.) 

------------------------------------------------------------------------------

3.0  ACCESSING THE GAME I/O PORT DIRECTLY

3.1  How it works

   The game port is accessed through a single 8-bit I/O port, 201h.  
(Officially, ports 200h through 20Fh are for the game port; only 201h is used, 
however.  The rest of these ports aren't used by the game port but maybe there 
are other things that use them [?].)  When you read an 8-bit value from port 
201h, here's what the bits are (for the analog joystick; see the sections on 
the Gravis GamePad [section 5] and the paddles [section 6] for information on 
those controllers).  Be aware that the game port itself has no idea what is 
connected to it; it's the controller that gives it the bits that you get 
through port 201h. 

        Bit     Description
         0      Joystick A x-coordinate
         1      Joystick A y-coordinate
         2      Joystick B x-coordinate
         3      Joystick B y-coordinate
         4      Status of joystick A button 1 (1=not pressed, 0=pressed)
         5      Status of joystick A button 2 (ditto)
         6      Status of joystick B button 1 (ditto)
         7      Status of joystick B button 2 (ditto)

   Reading the joystick button status is very easy; you simply IN from port 
201h and the top 4 bits of AL will be the button status.  (This takes a 
whopping two instructions; again, see button_status in JOYSTICK.ASM.) 
   You're probably wondering how the x and y coordinates of the joysticks can 
fit within single bits, especially for the analog joystick which can detect 
many x and y coordinates.  This is the slow part about reading the joystick 
position and it's a pain to write a routine to do that that's very optimized.  
(Look in JOYSTICK.ASM and you'll find routines to do that, already there for 
you to use and modify; they are read_1_joystick and read_2_joysticks.  It's 
much better to rely on these than the ROM BIOS routines which can be horribly 
inaccurate.) 
   To read the joystick coordinates, first you write a value to the 8-bit port 
201h.  It doesn't matter what the value is, just as long as you write a value.  
This does what's called firing the joystick one-shots.  The four bottom bits 
of port 201h will immediately become 1.  You read the joystick port over and 
over again and time how long it takes for the bits to turn 0.  The bits do not 
become 0 all at once; each one changes from 1 to 0 in an amount of time 
(elapsed time after you wrote the value to port 201h) proportional to the x or 
y coordinate that that bit represents. 
   Yes, I know what you're thinking.  That's a pain in the gluteus maximus.  
For one thing, that might be slow especially if you're reading the joystick 
positions several times a second, (it takes the same amount of time on every 
computer regardless of speed).  It would be nice if there were separate I/O 
ports for each coordinate where you read the port and that's the value right 
there.  But this is a lot easier for the hardware engineers. 
   The reason the ROM BIOS routine for reading the joystick position is slow 
is because it reads the four joystick coordinate bits one at a time; it will 
fire the joystick one-shots, time how long it takes for bit 0 to change from 1 
to 0, fire the joystick one-shots again, time how long it takes for bit 1 to 
change from 1 to 0, and so on.  That's not very efficient; the fastest 
possible routine for reading the joystick position would fire the joystick 
one-shots once and then time all four bits at once.  That's kind of hard to do 
considering that even on slow computers you want the timing to be as accurate 
as possible but at the same time the computer has to sort out which bits 
changed when, and which coordinates they would represent.  JOYSTICK.ASM,
included in this archive, has a routine (read_2_joysticks) that will time all 
four joystick coordinate bits at once.  It might not be very accurate on 
slower computers, however, because many timer chip counts might pass by on 
each run of the loop while the CPU tries to figure out what to do about the 
bits in the joystick port value that changed.  But if you're only going to 
read joystick A, you can use read_1_joystick instead which is more accurate on 
slower computers because the loop size is smaller and uses registers instead 
of memory operands to save the coordinates it's figured out so far.
   Be aware that if a joystick isn't connected, the bits representing that 
joystick will either be 0 and stay 0 or will be 1 and stay 1.  If the bits for 
a joystick are 1 and don't become 0 within a reasonable amount of time, assume 
that the joystick isn't connected or that something's wrong with the joystick.  
Just how long is a "reasonable amount of time" ?  See section 3.2.2. 
   Note: Whenever you fire the joystick one-shots, you have to wait for all 
four 1-bits to turn 0 before you can fire the joystick one-shots again.  

3.2  Timings

   In your routine for reading the joystick position, you should use the timer 
chip as a way of finding out the length of time between when you fire the 
joystick one-shots and a bit changes to 1.  

3.2.1  Lengths of time

   Have your joystick-reading routine count the number of timer chip clock 
ticks (there are 1193180 ticks per second) that pass between when you fire 
the joystick one-shots and when the bit turns from 1 to 0.  Then have it 
divide this value by 16.  This will be the value for the coordinate you're 
reading.  (Actually you don't have to use 16/1193180's of a second as the 
units; you can use any units you want for the coordinates of the joystick.  
However, these are the units which the values returned by the ROM BIOS 
joystick-reading function are in, they're the units used in this document 
whenever joystick x or y coordinates are given, and they're also the units 
used by the functions in JOYSTICK.ASM.

3.2.2  How long is too long?

   If you fire the joystick one-shots, and the 1 bits don't turn to 0 within a 
normal amount of time (or don't turn to 0 at all), something must be wrong 
with the joystick port or the joystick(s).  How long is a reasonable amount of 
time before assuming that something's wrong?  The maximum x or y coordinate 
value that you can get back from the ROM BIOS is 1FFh.  On my joystick, 
coordinates don't usually go past 100 or 150.  I guess 1FF0h clock ticks 
after when you write to the joystick port would be a good time to assume that 
something's wrong.
   Of course, this could also depend on what your program expects the maximum 
possible x or y coordinate to be; it gets this information from whenever it 
calibrates.  But the length of time after you fire off the joystick one-shots 
needs to be considerably more than what the program considers to be the 
maximum coordinate before it cries wolf.  For example, if during calibration 
(see section 8) the program found out that the maximum x-coordinate returned 
by the joystick was 140, and then during the program the 1 bit hasn't changed 
to 0 by the time 140*16 clock ticks have intervened, don't assume something's 
wrong yet; wait until at least 30*16 more clock ticks, perhaps, and if the 1 
bit changes to 0 within that time, your program can treat this extraordinarily 
high x coordinate to be the same as 140.  Remember, the joystick is not very 
exact.
   In the XT ROM BIOS, the ROM BIOS waits for a certain number of runs of a 
loop to happen before it assumes that there's an error; but that's not a good 
way to do it because that's processor-speed specific.

------------------------------------------------------------------------------

4.0  INTERPRETING THE JOYSTICK X AND Y VALUES

4.1  Now for the hard part...

   Analog joysticks are not very exact.  Their values can "float" around over 
periods of time, and constantly require calibration, both on the joystick and 
by the program.  The maximum x-coordinate is about 146 on my joystick (which 
is a Kraft QuickShot), and the maximum y-coordinate is about 154, but the 
routine in my ROM BIOS which reads the joystick values is not very accurate at 
all, and the maximum y-coordinates can jump around all the way from 105 to 
155!  And then, of course, turning the calibration knobs on my joystick could 
change it somewhat, and on a different brand or model of joystick the ranges 
might be very different.  According to "Advanced MS-DOS Programming" by Ray 
Duncan, the coordinates should be in the range 0 to 416 for a 250 KOhm 
joystick.  I'd appreciate it if people could please give me the values they 
get for their joysticks.
   Maybe the only thing you can be certain of is that higher x-coordinates are 
right and that higher y-coordinates are down, and that the coordinates are 
evenly spaced (i.e. moving the joystick the same amount in a particular 
direction makes the coordinates change the same amount, more or less, no 
matter what position the joystick was in to begin with).  If the joystick 
stays in a particular direction, the x- and y-coordinates will probably jump 
around by 1 or 2; you can't expect the joystick values to be precise all the 
way to the least significant bit.  This is probably caused by vibration of the 
joystick (or of the hand of the one holding it) and by the simple way in which 
the joystick converts the potentiometer output to timing outputs (not by 
anything fancy like a timing chip with an analog-to-digital converter, unless 
any of the really nice joysticks do this, but probably with a simple capacitor 
circuit of some sort).

4.2  Calibration

   How do we solve this problem?  Obviously the joystick cannot be used for 
very precise control (if you need very accurate and precise control like for a 
drawing program, the mouse would be a better input device).  However, a way to 
resolve the differences in coordinate ranges is to have a joystick 
calibration routine somewhere in your program.
   If you have played games that use the joystick (and the joystick isn't 
used for much other than games), surely you have seen calibration screens.  
They are usually in the configuration menus of the game (or the game does its 
joystick calibration every time you start the game, but that's a pain for the 
user because that has to be done every time the game is started).  Calibration 
is when the game finds out what normal x and y coordinates are for different 
positions on your joystick.  That way, during the game, it can know what sort 
of values to interpret as what.  

4.2.1  How to calibrate - the not-so-good way

   One way to calibrate the joystick is to ask the user to center the joystick 
and press the button.  When the button press is detected, the program reads 
the coordinates of the joystick.  Now the program will know that if the 
coordinates of the joystick are ever close to this value, the joystick can be 
regarded as being in the center.  This method doesn't require much user 
intervention; as a matter of fact, one game assumes that the joystick is 
centered when you start the game because it just reads the joystick 
coordinates upon startup.  However, this method of calibration isn't very good 
because it can't figure out what good coordinates for left, right, up, or down 
would be.

4.2.2  How to calibrate - a better way

   A better way to calibrate asks the user to move the joystick to its upper-
left hand position and press the joystick button.  When the user presses the 
joystick button, the program reads the joystick coordinates and assumes that 
they are good minimum x and y values.  Then the program asks the user to move 
the joystick to its lower-right hand position and press the button.  When the 
user presses the joystick button, the program reads the joystick coordinates 
and assumes that they are good maximum x and y values.
   Some games that calibrate the joystick this way ask the user to press 
button 1 when the joystick is in its upper-left hand corner, and button 2 when 
the joystick is in its lower-right hand corner.  This might be handy in order 
to make sure that the user knows which button is what, and in order to make 
sure that both buttons are responding.

4.2.3  How to calibrate - digital type joysticks

   Some games don't take advantage of the fact that the joystick is analog as 
opposed to digital.  If the joystick is to the right, the character runs 
right, but always at the same speed, regardless of how far to the right the 
joystick is; if the joystick is to the left, the character runs left at the 
same speed; if the joystick is near the center, the character doesn't move at 
all.  If your application that uses the joystick is going to do this, a better 
way to calibrate might be to ask the user to move the joystick to the upper-
left hand corner, press the button, move the joystick to the lower-right hand 
corner, press the button, center the joystick, and press the button.  This 
way, you'll have a more accurate determination of which direction is the 
center.  (You shouldn't do this if you're going to use the joystick as an 
analog joystick, however; this would make it very hard to interpret joystick 
coordinates in that case.)

4.2.4  When things go wrong...

   If the maximum x value from calibration turns out to be less than or equal 
to the minimum x value, or the maximum y value is less than or equal to the 
minimum y value, then something went wrong (either something's wrong with the 
joystick or the port, or the user didn't follow the calibration instructions 
correctly!)  In this case, you should just give some sort of error message 
saying that calibration failed. 

4.2.5  Recalibration

   Remember that the joystick values might float around even in the middle of 
a program.  You might calibrate the joystick at the beginning of a game, and 
ten minutes into the game, you let go of the joystick and let it go to the 
center position, and the character on the screen moves left.  The joystick 
requires constant recalibration which can be a real pain.  If you're writing a 
game that uses the joystick, however, let there be some way by which the user 
can recalibrate the joystick in the middle of the game, without having to 
start the game over. 

4.2.6  The calibration knobs on the joystick

   The calibration knobs on the joystick modify the joystick values to a 
certain extent.  When the joystick knobs are adjusted so that the center of 
the joystick has coordinates that are near the maximum or minimum x or y 
coordinates, the joystick cannot detect as many positions because joystick 
positions that go off the edge tend to be "clipped."  Therefore, it might be a 
good idea to ask the user to also adjust the calibration knobs on the 
joystick, and you might give some sort of pixel display which shows whatever 
values the joystick is currently returning so that the user can adjust the 
joystick to give x and y coordinates for the center that are as near to the 
center of the pixel display as possible.

4.3  Interpreting the values

4.3.1  Analog

   Now that your program knows what minimum and maximum x and y coordinates 
are from calibration, whenever the joystick is read during the program, how 
does it know what to interpret the values as?  Here you're going to be using 
some linear interpolation.  If the x value is halfway between the minimum and 
maximum x values, and the y value is halfway between the minimum and maximum 
y values, you can assume that the joystick is centered.  (Don't assume that 
the joystick is exactly halfway between, though; leave a certain range of x 
and y values which are centered.)  Likewise, if the x value is 3/4 of the way 
from the minimum x to the maximum x, the joystick is 3/4 of the way to the 
right.  If any of the coordinates turn out to be more than the maxima, or less 
than the minima, then just assume them to be equal to the maximum or minimum 
coordinates. 

4.3.2  Digital

   If your program is using the joystick as a digital joystick, then your 
program is probably just going to have exact cutoff x and y coordinates for 
determining which position the joystick is in.  Here's an illustration (ASCII 
doesn't make it very easy to do this...)

   +--------+--------+--------+ <- minimum y value
   |        |        |        |
   |   1    |   2    |   3    |
   |        |        |        |
   +--------+--------+--------+ <- 1/3 of the way from the min y to the max y
   |        |        |        |
   |   4    |   5    |   6    |
   |        |        |        |
   +--------+--------+--------+ <- 2/3 of the way from the min y to the max y
   |        |        |        |
   |   7    |   8    |   9    |                         1=upper-left
   |        |        |        |                         2=up
   +--------+--------+--------+ <- maximum y value      3=upper-right
            |        |                                  4=left
   |        |  2/3 from min   |                         5=centered
minimum x   |  y to max y     maximum x value           6=right
  value     |                                           7=lower-left
            |                                           8=down
1/3 from min x to max y                                 9=lower-right

   Of course, the fractions could be anything you wanted them to be.
   If you had calibrated the joystick the way described in 4.2.3, it might be 
more like this:
 
   +--------+--------+--------+ <- minimum y value
   |        |        |        |
   |   1    |   2    |   3    |
   |        |        |        |
   +--------+--------+--------+ <- 2/3 from minimum y to center y
   |        |        |        |
   |   6    |   5    |   4    | <- center y value
   |        |        |        |
   +--------+--------+--------+ <- 1/3 from center y to maximum y
   |        |        |        |
   |   7    |   8    |   9    |
   |        |        |        |
   +--------+--------+--------+ <- maximum y value
   |       /    |     \       |
minimum x  | center x |     maximum x
           |          |
2/3 from min x     1/3 from center x
to center x        to max x

   Again, of course, the fractions can be whatever you want them to be!

------------------------------------------------------------------------------

5.0  GRAVIS GAMEPAD

5.1  Description

   The Gravis GamePad is a digital controller that connects to the regular 
joystick port.  It looks similar to the Super Nintendo pad.  It has four 
buttons, which can be used either as four buttons or as two normal buttons and 
two turbo buttons.  Whenever you press a "turbo" button, it's like pressing 
the normal button that it corresponds to except that a timer of some sort in 
the joystick rapidly turns the signal for the button on and off, making rapid-
fire in a game easy.  A switch on the GamePad can make it suitable for either 
left-handed or right-handed play; you can hold the joystick the other way, 
and the joystick will invert which pad direction is which and which button is 
which.  Note that both the rapid-fire and the left/right-handed switching of 
the joystick controls are invisible to the program; the software does not (and 
can not) find out which modes the GamePad is in, and it doesn't need to invert 
its idea of which button is which or whatever if the joystick is held the 
other way because the joystick does all that.  If a turbo button is pressed, 
it only appears to the software as a joystick button being turned on and off.

5.2  Digital joystick

   A Gravis GamePad is not very suitable for playing games which use the 
joystick as an analog joystick, because there is only one up position, only 
one left position, and so on.  The GamePad can only detect nine positions of 
the pad--the center, up, down, left, right, and four intermediate positions.  
Probably, the values on a Gravis GamePad don't float around very much, but I'm 
not sure about this because I don't have a Gravis GamePad to try this with.

5.3  Programming the Gravis GamePad

5.3.1  Buttons

   When the Gravis GamePad is in four-button mode, the third and fourth 
buttons appear to be the first and second buttons of joystick B.  This means 
that if you read from I/O port 201h to get the button status (or call the ROM 
BIOS function to do this), bits 4 through 7 will give the status of GamePad 
buttons 1 through 4 in that order (1 means the button is not pressed, 0 means 
the button is pressed).  If you connect more than one Gravis GamePad to the 
computer at a time, buttons 3 and 4 of each joystick don't do anything for 
this reason, since there aren't enough bits for all the buttons.  (At least, 
that's what I think happens; unless both buttons 3 and 4 on joystick A and 
buttons 1 and 2 on joystick B trigger the same bits, but this would depend on 
the Y-connector that you use to connect the two GamePads to the game port.)  
In two-button mode, buttons 3 and 4 act like turbo buttons for buttons 1 and 
2, but when a turbo button is pressed, it only appears to the program that the 
button is being pressed and released over and over.  Turbo doesn't mean 
anything special from the program's point of view.
   
5.3.2  The pad itself

   Since the pad is digital and can only detect nine positions, and there are 
no calibration knobs on the Gravis GamePad, the values that you get from 
reading it probably don't "float around" very much.  (I'm not sure about this 
because I don't have a Gravis GamePad to test this on; if you have one, please 
let me know about the typical values that you get for each of the nine pad 
positions.)  If your program is going to use the joystick as a digital 
joystick, it probably doesn't even have to know whether or not there is a 
Gravis GamePad (unless you plan to use buttons 3 and 4).  After all, it 
returns values that are similar to those values that a regular joystick would 
return in those nine positions, so if your program is going to use the 
joystick as a digital joystick, after calibration it can treat all joysticks 
the same way.

------------------------------------------------------------------------------

6.0  PADDLES

6.1  Description

   A paddle is another type of controller that can be connected to the game 
port.  It is quite different from an analog or digital joystick, in that, 
while joysticks have two axes (x and y), the paddle only has one axis.  A 
paddle consists of a knob which you turn left and right, and one button.  
Paddles are suitable for games in which you are only going to move something 
on the screen left and right (or up and down), such as Pong-type games in 
which you move something left and right to catch a ball and bounce it back at 
the other player's paddle on the screen.  The paddles that you connect to the 
game port are probably named such because of table-tennis paddles.  Up to four 
paddles can be connected to the game port at a time.

6.2  Programming

6.2.1  Getting the button status and the coordinates

   When you read from I/O port 201h to get the status of the paddles, the bits 
will have the following definitions:

        Bit     Description
         0      Paddle A coordinate
         1      Paddle B coordinate
         2      Paddle C coordinate
         3      Paddle D coordinate
         4      Status of paddle A button (1=not pressed, 0=pressed)
         5      Status of paddle B button (ditto)
         6      Status of paddle C button (ditto)
         7      Status of paddle D button (ditto)
   
   Of course, you can also call the ROM BIOS functions to get the status of 
the paddles.  The bits for the buttons will be the same as above, and for the 
function which gives you the joystick coordinates, instead of getting the 
joystick A and B x and y coordinates in AX, BX, CX, and DX, you will get the 
coordinates of the four paddles (with a 0 coordinate for a paddle which isn't 
connected or isn't responding).  
   Getting the coordinates of the paddles is very much the same as getting the 
coordinates of the joysticks.  You fire the one-shots by writing any 8-bit 
value to port 201h, and then you time how long it takes for the 1 bits in bits 
0-3 to change to 0 (the bit for a paddle which isn't connected is undefined, 
but will probably be 0 and stay 0 or be 1 and stay 1).  The timings are 
probably very much the same as for a joystick.  Of course, if you are writing 
a routine to read the coordinate of just paddle A, the routine will probably 
be relatively small and efficient because it only has to look at one bit, as 
opposed to the routine for reading the joystick coordinates which has to time 
at least 2 bits.

6.2.2  Interpreting the coordinates

   Since I don't have a paddle (and I don't know anyone who has one; I only 
know from my reference that they exist), I wouldn't know this for sure, but it 
is most likely that when the paddle is in its rightmost (most clockwise) 
position, the coordinate of that paddle is the highest, and that when the 
paddle is in its leftmost (most counter-clockwise) position, the coordinate 
of that paddle is the lowest.
   I don't know whether or not paddles have calibration knobs, or whether or 
not the lower and upper bounds of the coordinates are very well defined, but 
since I don't know what typical coordinates are, or whether or not coordinates 
are very constant across paddles (probably not), you probably need calibration 
of some sort.  Probably the program would ask the user to put the paddle in 
its leftmost position and press the button, and then it would read the paddle 
coordinate; then it would ask the user to put the paddle in its rightmost 
position and press the button, and then it would read the paddle coordinate 
again.  Calibration fails, of course, if the upper bound is less than or equal 
to the lower bound.  The value halfway between these two values can be assumed 
to be the center. 

------------------------------------------------------------------------------

7.0  DETECTING THE GAME PORT AND CONTROLLERS

7.1  Detecting the game port

   How do you tell whether or not there's a game port connected to the system?  
One way is to read from I/O port 201h, and if the value is 0F0h, there is a 
game port connected to the system, otherwise there isn't (unless there are 
joysticks connected which are giving different values; if you haven't fired
the joystick one-shots recently this shouldn't be the case).  This is not 
really a good way to do it because some game ports could be nonstandard and 
return different values if the joysticks are not connected.  My joystick port 
is this way; if no joysticks are connected and I have the computer read from 
I/O port 201h, the value it gets is 0F3h.
   The computer's equipment status word (which you can get by reading the word 
at 0040h:0010h or by doing an int 11h which returns this word in AX) contains 
a bit that tells (or is supposed to tell) whether or not there is a game card 
(on machines other than PS/2's).  If this bit is 1, there is a game card; if 
it's 0, there isn't.  This bit is bit 12 of the word.  Beware; bit 12 of the 
equipment status word is unused (or used for something else) on PS/2's, so 
this is not really a good way to check for a game port.  When the computer is 
booted up, the BIOS checks to see whether or not there is a game port (on 
XT's and probably on most other machines, it uses the same method described 
above, which isn't really the best way), and it sets this bit accordingly.
   A better way to detect whether or not there is a game port is to read the 
port, and if the value is 0FFh (the value you get from any I/O port to which 
no device is connected), there is no game port; otherwise there is.  Make sure 
that you haven't fired the joystick one-shots recently when you do this so 
that if there is a game port and joysticks are connected, 0FFh isn't the 
actual value that is being returned.  There's already a C-callable function in 
JOYSTICK.ASM which does this (detect_game_port).  This may not be 100% 
reliable, however, so be sure to give the user a way to override whether or 
not the program thinks there's a game port. 
   In any case, the program will probably not need to know whether or not 
there is a game port, just whether or not the controller is connected.  
So it would probably just be easier to detect whether or not a controller is 
connected in the first place since a game port isn't much use without 
something connected to it.  
 
7.2  Detecting joysticks

   There really isn't any way that the program can tell which type of 
controller is connected to the game port.  The program probably has to ask the 
user for this information.  If your program is going to use the joystick as a 
digital joystick, it probably won't need to know whether or not there is a 
Gravis GamePad connected (unless it could use buttons 3 and 4 in this case). 
   However, there is a way to tell whether or not controllers are connected, 
and if so, how many (assuming that you know whether the controllers are 
paddles or joysticks).  Fire the one-shots by writing any value to the 8-bit 
port 201h.  Then continue to read from port 201h, and if any of the lower 4
bits changes values within a "reasonable amount of time" (see section 3.2.2), 
the controller that it goes to is connected.  The joystick-reading procedures 
in JOYSTICK.ASM can be used for detecting joysticks because they return 0FFFFh 
for the coordinates of the bits in the joystick port value that never changed.
   One method which you should NOT use to detect joysticks: Call the ROM BIOS 
function to read the joystick values, and if a joystick coordinate that it 
returns is not 0, that joystick is connected.  You shouldn't use this method.  
You see, if the bits for a joystick which isn't connected are always 0, the 
ROM BIOS function might realize that these bits are 0 on the first or second 
run of its timing loop and assume that these bits had just turned 0 (when in 
fact they were always 0), and therefore return a really low value like 1 or 2 
but not 0.  On my computer, although I only have one joystick connected to the 
game port, the ROM BIOS function for getting the joystick coordinates always 
returns 1 or 2 for the x and y coordinates of joystick 2.  You have to 
actually detect a CHANGE in a bit for a controller in order to assume that the 
joystick is there.  The joystick routines in JOYSTICK.ASM look for bit 
changes, instead of noticing that a bit is 0 and thinking that it had just 
turned 0.  This is probably more reliable than the method for telling whether 
or not a game port is connected to the machine, but you might still want to 
give the user a chance to override what the program thinks. 

------------------------------------------------------------------------------

8.0  PINOUTS

8.1  Introduction

   For you hardware hackers out there, (no, I'm not one), this section is 
about the pinouts on the game port.  The game port is useful for other things 
than connecting joysticks or other controllers; it could be used for 
diagnostic purposes since reading from I/O port 201h simply gives the status 
of certain pins on the game port.
   Here's one thing which I need help on from someone: The list of pins on the 
game connector that I have doesn't say anything about a pin which does 
anything whenever the joystick one-shots are fired.  However, the joystick has 
to know somehow whether or not the one-shots are fired so it can start timing 
so that it knows when to turn the coordinate bits from 1 to 0.  Help!
   When a joystick button is being pressed, the bit for that button is 0, and 
when the button is not pressed, the bit is 1.  You would expect it to be the 
other way around.  The reason is probably because the voltages that the 
computer uses for signals are backwards - a higher voltage means a 0 and a 
lower voltage means a 1.  (Can anyone give me precise values for the 
voltages?  I would expect +5V with respect to ground to be a 0 bit and 0V to 
be a 1 bit; this explains why the buttons return a 0 when pressed and 1 when 
not pressed, since they are normally open buttons.  I need to test this with a 
voltmeter some time...)
   Remember, to the game port itself, there is no functional difference 
between the pins that give the joystick position and the pins that give the 
button status; the circuitry within the joystick is what converts the outputs 
from the variable resistors that read the position to high and low signals 
whose timings are based on them.  All the game port itself does is take the 
high and low signals given to it on the pins and convert them to 0's and 1's 
when you read port 201h, and fire the joystick one-shots somehow when you 
write to that port.

8.2  Pinouts

   The computer's connector is a female DB-15.  I'm not sure which pins are 
which numbers, but a male DB-15 on something that you connect to the game port 
would probably have the numbers of the end pins marked.
                                
Pin number      What it does
----------      ------------
    1           +5V DC
    2           Bit 4 of I/O port 201h
    3           Bit 0 of I/O port 201h
    4           Ground
    5           Ground
    6           Bit 1 of I/O port 201h
    7           Bit 5 of I/O port 201h
    8           +5V DC
    9           +5V DC
    10          Bit 6 of I/O port 201h
    11          Bit 2 of I/O port 201h
    12          Ground
    13          Bit 3 of I/O port 201h
    14          Bit 7 of I/O port 201h
    15          +5V DC

   All signals that come into the game port (the bits of the I/O port) are 
"active high," whatever that means.

------------------------------------------------------------------------------

9.0  HOW TO CONTACT ME

   Please let me know of anything I left out (I know I'm missing some info 
like the joystick one-shots on the pinouts, and definite voltages for the 
pinouts [high and low] with respect to ground) and anything that's inaccurate 
in this document.  Any comments or suggestions are appreciated!  I can be 
contacted at: 

SnailMail: 713 N.W. 141 St., Edmond, OK, 73013-1920.

FidoNet: Usually I'm on the lookout for any messages addressed to me on the 
80XXX echo. 

InterNet: emil.gilliam@oubbs.telecom.uoknor.edu


