InterWave GAME API Specification (Preliminary)

    This document contains an overview of the InterWave GAME API.  
This interface will aid in communication between TSRs and applications 
and provide an interface to a library of game funcions.
    By calling the GAME API, an application has the ability to communicate 
directly with a resident TSR or application running in the background.  
This gives the caller the ability to perform some functions to aid in 
gaining access to resident game support.  Also, a third party program can 
use this API to free and restore resources from currently loaded software.
    By listening to the communication through the GAME API, an application 
can also get broadcast messages reflecting changes in the state of the 
machine or the soundcard.
    By hooking into the GAME API, an application becomes part of a network 
of resident InterWave programs and can be accessed generically as such.
    The GAME API contains three sets of functions: 

        - InterWave Program Communication 
        - InterWave GAME Communication 
        - InterWave Broadcast functions

    The interface to these functions sets is divided over two software
interrupts.  The bulk of the communication is done over the DOS Multiplex
interrupt INT 2fh.  Most DOS programming guides have ample information on
using this interrupt vector so its use does not conflict with any other 
programs.  The rest of the functions, which include direct sound interfaces, 
are accessed through a given software interrupt.  The interrupt number is
determined when the GAME API is successfully opened (See INT 2fh Function
21h: Game Device Open).  This interrupt vector will be referred to from 
here on as the GAME Vector.  All vectors and pointers mentioned in this 
specification are to be utilized from real mode only.
    The implementation of the GAME API differs depending on the purpose of 
the application using it.  If the application is a game, it need only make 
calls to the API and should have no need to hook the int 2fh vector and 
installing an InterWave GAME API handler.  But, if the application is, for 
example, a TSR for controlling some or all of the InterWave, it needs to 
both make calls to and hook the int 2fh chain.  
    The following will be a function by function description of the GAME API.
Some sample code from a test program will be included to show how the API 
should be used.  Be aware that much of the functional description is from
the point of views of both a program supporting the GAME API as well as that
of an application using the API.

INT 2fh Function 0: INT 2fh ID Install Check:
--------------------------------------------------------------------------------
    This function is used as part of the Microsoft INT 2fh specification.
INT 2fh is used by loading an ID number into register AH and a function 
number in register AL and calling INT 2fh.  Function 0 is always used to 
determine if an INT 2fh ID is occupied.  By calling this function with the 
ID, an application can determine if that ID is currently in use based
on the return value.  If a -1 (FFh) is returned in register AL, the ID is 
used.  Otherwise, any other value means the ID is open.  The application 
can further determine if the program currently using that ID is an InterWave 
program by examining other registers looking for a particular InterWave stamp.
If this stamp is found, then an InterWave program is currently using that 
INT 2fh ID number and the calling application MUST use it. 
    This function is often used in a loop searching a range of possible INT
2fh IDs until the first InterWave program is found or the end of the range
is reached.  In the latter case, the first INT 2fh ID found that is not
occupied will be used and the new program will be the first InterWave
application to install itself on the INT 2fh chain recognizing that ID.
The range of INT 2fh IDs that will be searched will be CDh to ECh.  This will
provide ample room for an application to find a free ID.
    If a resident program supporting this GAME API already installed on 
the INT 2f chain, receives a Function 0: Install Check, it must set register
AL to FFh and register pair DX:SI to the string "ETEK" (DX="ET" and
SI="EK").  Control will then be returned to the calling program and not
chained to the previous INT 2f handler.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            
        AL   - 0                     AL   - FF     Occupied
        DX   - "IW"                  DX   - "ET"   Stamp
        SI   - "VE"                  SI   - "EK"

TEST CODE:
/**
 ** test_2f_id() will return TRUE if id is currently an occupied INT 2fh ID.
 **/
#define IW 0x4957  /* "IW" */
#define VE 0x5645  /* "VE" */
int test_2f_id(int id)
{
    union REGS regs;

    regs.h.al = 0;    /* function 0 */
    regs.h.ah = id;   /* INT 2fh ID */
    regs.x.dx = IW;   /* load dx:si with anything BUT "ETEK" */
    regs.x.si = VE;
    int86(0x2f,&regs,&regs);
    if(regs.h.al == 0xff) /** This one's occupied **/
        return TRUE;
    else
        return FALSE;
}

INT 2fh Function 1: Get Number Of InterWave Programs / Get Installed Program
                    ID Number
--------------------------------------------------------------------------------
    This function is used to determine the number of InterWave programs
currently resident in memory and supporting the InterWave GAME API.  In
order to be able to access each program individually and as single entities,
each program must have an ID number assigned to them which only they respond to
and all other InterWave programs ignore.  The number returned from this
function is the number each program uses when it loads and installs an
InterWave GAME API handler.  This number is the Installed Program ID number.  
    If a program is not going to install its own handler but only needs to 
talk to or find a specific program in memory, it will call this function to
get the number of InterWave programs resident.  It will then call another
INT 2fh function (like Function 2: Get Program Status and Information) with
Installed Program ID numbers starting at 0 and up to but not equaling the number
of resident InterWave programs until it finds the program it wants.  This
may be used, for example, to locate a specific program like SBOS, clarify 
it from other programs, and access it.
    If a program is going to install its own GAME API handler, it will use
the new Installed Program ID number as its own.  For example, the first 
program that loads will realize that it is the first by not being able 
to find any other InterWave programs on the INT 2fh chain by using 
function 0.  It will then assign itself Installed Program ID number 0.  If 
a second program then searches the INT 2fh chain, it will find the first 
program already loaded and store the INT 2fh ID it used.  It will then 
call INT 2fh with the INT 2fh ID and function 1 to determine the number 
of InterWave programs already loaded and using this GAME API.  It doesn't 
know the number of programs loaded because function 0, Install Check, 
only returns that the INT 2fh ID is used and not how many programs are using 
it.  The number returned will be 1.  The new program will then store a 1 as
its Installed Program ID number.  Any program from this point on calling
the GAME API with the correct INT 2fh ID number and Installed Program ID
number 1, will then be talking directly to this newly installed program.
    If this new program receives a function 1 call through its new GAME API
handler, it will simply increment register BX and chain the INT 2fh call.
This function is different from others in that control is chained to
the previously installed INT 2fh handler and not immediately returned to the 
calling handler.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            
        AL   - 1                     
        BX   - 0                     BX   - Number of IWave Programs Loaded

TEST CODE:
/**
 ** Will call INT 2f function 1 - Get Number of InterWave Programs
 ** This function returns the number of programs loaded that respond to the 
 ** InterWave GAME API
 **/
int get_num_tsrs(int id)
{
    union REGS regs;

    regs.h.al = 1;
    regs.h.ah = id;
    regs.x.bx = 0;
    int86(0x2f,&regs,&regs);
    return regs.x.bx;
}

INT 2fh Function 2: Get Program Status and Information
--------------------------------------------------------------------------------
    This function is used to get specific information about an InterWave
program in memory.  Only one program in memory will respond to this
function on each call.  It is used to get information such as a pointer to
an identification string, and a status bit field showing resources used, 
and if game functions are supported.
    If the calling function needs to locate a specific program or a specific 
type of program in memory, it can call this function with all valid
Installed Program ID numbers (See INT 2fh Function 1: Get Installed Program ID
Number) and test the results of each call.  If for example, the application 
is a DAC driver and wants to support the CODEC in native mode it would 
first poll each resident InterWave driver and call it with this function 
testing for the CODEC bit to be on.  If it is on for any driver or resident 
application, INT 2fh Function 3: Suspend Program must be called to free the 
CODEC hardware.  Once the driver is done with the CODEC, and assuming it still 
has control of it, it must call INT 2fh Function 4: Wake Program to restore 
the connection of the original program to the CODEC.
    Caution must be taken in setting the hardware allocation bits for this
function call.  If any program specifies that it is using either section of
the InterWave hardware, it MUST be prepared at any time to relinquish
control of that hardware to another application requesting such through INT
2fh Function 3: Suspend Program.  It also must be prepared to specify a
usable base port, IRQ, and DMA channel (where applicable) to the calling
application.  Care must be taken with hardware allocation of this sort.  It
must be noted that it is possible that the SYNTH and CODEC can be programmed
to use the same IRQ.  Since it is not required that any chaining of handlers
or IRQ callback be issued, the IRQ lines must be different when the control 
of a hardware section is given away.  That may, in some cases, mean that
before the suspend call is granted, some hardware programming may have to be
done to separate the channels.
    This function is also used to determine if a specific program supports 
any game devices.  If bit 2 is on in register CX, the game device support is
present.  The Version number is there for backward compatability for future 
versions of the game functions and is only valid if game devices are supported.
    If this bit is on (bit 2), the program will support at least one game 
device.  A game device is a library of routines used to produce sound.  Each 
device is different in capability and function.  See INT 2fh Function 21h: 
Game Device Open for more details on each device.

FUNCTION SPECIFICATION:
        AH   - INT 2fh ID
        AL   - 2
        BX   - Installed Program ID  BX   - Game Functions Version (BCD BH.BL)
                                     CX   - Program Status
                                     ES:DI- Pointer to ASCIIZ ID string

     Bit fields in CX are as follows (1 is TRUE):
        [0]  - Using Synthesizer Section of InterWave Card
        [1]  - Using CODEC Section of InterWave Card
        [2]  - Supports at least one Game Device (see fcts. 21h and 22h)

TEST CODE:
/**
 ** This will call int2f function 2 - Get Program Status and Information
 ** It will print out the id string and wheather or not it is using the
 ** CODEC and synth.
 **/
int get_status(int id, installed_prog_id)
{
    union REGS regs;

    regs.h.al = 2;
    regs.h.ah = id;
    regs.x.bx = installed_prog_id;
    int86x(0x2f,&regs,&regs,&sregs);

    printf("    ID String --> \"%Fs\"\n",MK_FP(sregs.es,regs.x.di));
    printf("    STATUS    --> ");

    if(regs.x.cx & 0x01) 
        printf("Using SYNTH - ");
    else 
        printf("NOT Using SYNTH - ");

    if(regs.x.cx & 0x02) 
        printf("Using CODEC\n");
    else 
        printf("NOT Using CODEC\n");

    if(regs.x.cx & 0x04) 
        printf("                  Supports GAME Devices\n");
    else 
        printf("                  No Support For GAME Devices\n");

    return regs.x.cx;
}

INT 2fh Function 3: Suspend Program 
--------------------------------------------------------------------------------
    This function can be used to suspend a resident program which is
currently using the InterWave GAME API and has allocated sections of the
InterWave hardware.  It is the responsibility of the calling program to wake 
up the sleeping program once done with the resources.  This wake up call 
can be performed with INT 2fh function 4.
    The calling program can only request the release of one section of the
InterWave card at at time.  If control of either the CODEC or SYNTH sections
of the InterWave card is requested, the base port, IRQ, and DMA channel (when
applicable) will be returned.  This will be a standard approach for third 
party drivers to free resources.  This will not, however, be the method by
which a game will allocate hardware.  Under no circumstances should a game or
any application not providing any InterWave specific services (ie. emulation,
hardware function library, etc.) use hardware directly without allocating 
a game device and ONLY then if the game device is specified to be used in
that manner.  See INT 2fh Function 21h: Game Device Open.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            
        AL   - 3                     AL   - 0 (Suspended) Else (Fail)
        BX   - Installed Program ID  BX   - Base Port
        CX   - Requested Device      CL   - IRQ
                                     CH   - DMA - for CODEC only
     Values for CX are:
        01   - Just SYNTH
        02   - Just CODEC

TEST CODE:
void suspend_prog(void)
{
    char status;
    union REGS regs;

    status = get_status(int2f_id, 0);
    if(status & BIT1) /* If bit 1 is on, CODEC is busy */
        {
        regs.h.al = 3;
        regs.h.ah = id;   /* int 2fh id */
        regs.x.bx = 0;    /* choose installed program id 0 */
        regs.x.cx = 1;    /* request SYNTH */
        int86x(0x2f,&regs,&regs,&sregs);
		if(regs.h.al == 0)
            {
            syn_base = regs.x.bx;
            syn_irq  = (unsigned int)regs.x.cl;
            }
        }
}

INT 2fh Function 4: Wake Program 
--------------------------------------------------------------------------------
    This function is used only after INT 2fh Function 3: Suspend Program to
restore a program to its initial state.  It is up to the suspended program
to restore all that was suspended from the initial suspend call.  If for
some reason the wake call cannot pass, it is then up to the calling program
to notify the user through some standard method that the InterWave is now in
an unstable state and some appropriate action must be taken.  If for
example, the suspended program was SBOS and the calling program
inadvertantly broke SBOS so it could not somehow refresh its internal
status, SBOS will return a fail status on an attempt to wake.  The calling
program could call INT 2fh function 2: Get Program Status and Information
with SBOS's Installed Program ID number and format an error string for the 
user with the ID string returned in the es:di pointer.
    It must be assumed that the state of the machine (including the
InterWave card, PIC mask, etc.) after this call is in a significantly
different and unpredicatble state.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            
        AL   - 4                     AL   - 0 (Woken) else (Failed)
        BX   - Installed Program ID 

INT 2fh Function 5: Free Resident Device Driver
--------------------------------------------------------------------------------
    This function should only be called by startup code for a program trying
to free a copy of itself in memory.  It should never be called to free
another program.  To free another program of its resources, use INT 2fh
Function 3: Suspend Program.  It is not required that all programs support 
this procedure.  However, if the function is not required, a fail return
code must still be returned.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            
        AL   - 5                     AL   - 0 (Freed) else (Failed)
        BX   - Installed Program ID 

INT 2fh Function 21h: Game Device Open
--------------------------------------------------------------------------------
    This function is used to establish a connection to the program
which has been found to support game functions.  See INT 2fh Function 2: Get
Program Status and Information on how to determine if a program supports the
game functions.  If the calling program needs a MIDI device, the first 
device it should try to open should be the "MIDISIMPLE" device.  In order 
to open this device, the calling program would load a pointer to a string 
containing "MIDISIMPLE" (NULL terminated) just as it would for a disk file.  
If the open attempt fails, the device is already open or is not implemented 
in the current version of the game function interface.  If a previous 
application opened a device and did not close it, the device can not be 
reopened without closing it using the correct handle number.
    The real mode interrupt number passed back in register BX is the
communication vector for the remainder of the game functions if a software
interface is utilized.  Each function differs based on the device opened.  
Therefore, each call to the GAME Vector will vary based on the device it
is communicating with.
    There are currently three devices which applications can use to generate 
sound with the GAME API.  The names of the devices here are the strings 
which must be sent to INT 2fh Function 21h: Game Device Open.  The devices are:

  - MIDISIMPLE - Simple MIDI engine.  Byte oriented.

     FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            AL   - 0 (allocated) else (Failed)
        AL   - 21h                      
        BX   - Installed Program ID   BX   - Real Mode Interrupt Number
        ES:DI- ->"MIDISIMPLE"
                                     DX   - Device Handle

  - MIDICOMPLEX - Comples MIDI engine.  Patch Cacheing etc.

     FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            AL   - 0 (allocated) else (Failed)
        AL   - 21h                      
        BX   - Installed Program ID   BX   - Real Mode Interrupt Number
        ES:DI- ->"MIDICOMPLEX"
                                     DX   - Device Handle

  - DIRECTCODEC - Allocates CODEC for direct hardware writes.

     FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            AL   - 0 (allocated) else (Failed)
        AL   - 21h                      
        BX   - Installed Program ID   BX   - Base Port
        ES:DI- ->"DIRECTCODEC"
									 CL   - IRQ
                                     CH   - DMA - (4 for FIFO control)
									 SI   - FIFO Size (for FIFO only)
                                     DX   - Device Handle

    The "MIDISIMPLE" device has two functions.  Both functions proccess raw MIDI
data.  The data is passed to the processing application through the use of
the GAME Vector returned from INT 2fh Function 21: Open Game Device.  The
functions for MIDISIMPLE are described in APPENDIX A.
    The "MIDICOMPLEX" device supports more complex MIDI processing including
such things as dynamic patch loading.  The MIDICOMPLEX specification can be
found in APPENDIX B.
    The "DIRECTCODEC" device will allocate the CODEC and allow the application 
to do direct hardware writes to control digital output.  The hardware
specification for the CODEC can be found in the InterWave specification.
If the returned DMA channel is four, NO DMA services will be used.  This may
be the case for PCMCIA implementations.  In this case, the CODEC should be
programmed using its FIFO capability.  The size of the FIFO, in bytes, will
be returned in register SI.  If DMA will be used, SI will be zero.
    These devices can be thought of as disk files.  In order to use a 
device, one must open it and get a handle to it.  When it is done being 
used, it needs to be closed.  Through the duration of the applications use 
of the device, it will be referred to through a handle number.  As with a 
file, the handle is meaningless before the file is opened and after it is 
closed.  The device cannot be reopened without issuing a close.  It is up to
the supporting application to recognize which device each handle number
represents and parse the incoming data appropriately.

INT 2fh Function 22h: Game Game Device Close
--------------------------------------------------------------------------------
    This function is called when an application has finished using the
previously opened game device from INT 2fh function 21h.  It will fail if
the device is not open or if the handle is invalid.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        AH   - INT 2fh ID            AL   - 0 (closed) -1 (bad handle/not open)
        AL   - 22h
        BX   - Installed Program ID
        DX   - Device Handle

INT 2fh Function 80h: Mixer Settings Changed Broadcast Message
--------------------------------------------------------------------------------
    This function should not be called by any application program unless it
controls the InterWave mixer.  This function is intended as a broadcast
message only for those applications who care that the mixer has changed
values.  This is useful if an application is displaying the values in the
mixer and wants to keep them up to date.  If this message is received the
new mixer values must be read from the InterWave.

FUNCTION SPECIFICATION:
     Called With:
        AH   - INT 2fh ID
        AL   - 80h

TEST CODE:
void interrupt int2f_handler(void)
{
    if(_AH == INT2f_ID) && (_AL == 0x80)
        update_mixer_display();
}


APPENDIX A: MIDISIMPLE Specification

    Both of these functions are valid only if the following is true:  The 
handle used reflects a successfully opened MIDISIMPLE device and the 
GAME Vector called is valid as described in the specification for INT 2fh 
Function 21h: Game Device Open.

GAME Vector Function 1:  MIDI Byte Out
--------------------------------------------------------------------------------
    This function will send a single MIDI byte out to the game device to get
parsed and immediately acted upon.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        EAX  - 1                      EAX = 0 pass, -1 bad handle
        BL   - MIDI Byte
        DX   - Handle

GAME Vector Function 2:  MIDI String Out
--------------------------------------------------------------------------------
    This function will send a string of MIDI bytes out to the game device to
get immediately parsed.  There will be no timing information included in the
string.  The number of bytes parsed will be in register ECX.

FUNCTION SPECIFICATION:
     Called With:                  Returns:
        EAX  - 2                      EAX - 0 pass, -1 bad handle
        ES:EDI - Pointer to MIDI String
        ECX  - Count
        DX   - Handle


APPENDIX B: MIDICOMPLEX Specification

TBD
