/***************************************************************************
*       NAME:  2f.C $Revision: 1.1 $
**      COPYRIGHT:
**      "Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
** 
**                             (PRELIMINARY)
**
**  This is a test program to outline the test for and usage of the GAME API.
** 
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <dos.h>

/**
 ** These are the character values in dx:si for the install function
 **/
#define IW 0x4957
#define VE 0x5645
#define ET 0x4554
#define EK 0x454b

/**
 ** This is the range of 2fh ID numbers this program will test through
 **/
#define START 0x80
#define END   0xff

/**
 ** This is a midi string that will be sent to sbos to play (C major chord)
 ** 90h is note on channel 0
 ** 60 is note - middle c
 ** 7fh is velocity - loudest
 ** 64 is second note - e
 ** 7fh is velocity
 ** and 67 and 7fh are the note (g) and velocity for the third note
 **/
char midi_string[25] = {0x90,60,0x7f,64,0x7f,67,0x7f};
char midisimple[30] = {"MIDISIMPLE\0"};
char midicomplex[30] = {"MIDICOMPLEX\0"};
char directcodec[30] = {"DIRECTCODEC\0"};

/**
 ** Other globals
 **/
int synth_handle,codec_handle,swint;
union REGS regs;
struct SREGS sregs;
int reg_pid;
unsigned char int2f_id;

/**
 ** test_2f_id() will return TRUE if id is currently an occupied INT 2fh ID.
 **/
int test_2f_id(void)
{
    regs.h.al = 0;    /* function 0 */
    regs.h.ah = int2f_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 **/
        {
        printf("\nID# %X is occupied\n\n",int2f_id);
        return 1;
        }
    else
        return 0;
}

/**
 ** 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(void)
{
    regs.h.al = 1;
    regs.h.ah = int2f_id;
    regs.x.bx = 0;
    int86(0x2f,&regs,&regs);
	if(regs.x.bx == 1)
		printf("Found %d InterWave TSR on ID# %X\n",regs.x.bx,int2f_id);
	else
		printf("Found %d InterWave TSRs on ID# %X\n",regs.x.bx,int2f_id);
    return regs.x.bx;
}

/**
 ** This will call int2f function 2 - Get Device Status
 ** It will print out the id string and wheather or not it is using the
 ** CODEC and synth.
 **/
int get_status(void)
{
    regs.h.al = 2;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
    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 (CX = %xh)\n",regs.x.cx);

	return (regs.x.cx);
}

void suspend_synth(void)
{
    regs.h.al = 0x3;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
	regs.x.cx = 1;          /* synth */
    int86(0x2f,&regs,&regs);
	if(regs.x.ax)
		printf("        SYNTH Not Suspended \n");
	else
		{
		printf("        SYNTH Suspended \n");
		printf("            BASE: %xh\n",regs.x.bx);
		printf("            DMA:  %xh\n",regs.h.ch);
		printf("            IRQ:  %xh\n",regs.h.cl);
		}
}

void suspend_codec(void)
{
    regs.h.al = 0x3;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
	regs.x.cx = 2;          /* codec */
    int86(0x2f,&regs,&regs);
	if(regs.x.ax)
		printf("        CODEC Not Suspended \n");
	else
		{
		printf("        CODEC Suspended \n");
		printf("            BASE: %xh\n",regs.x.bx);
		printf("            DMA:  %xh\n",regs.h.ch);
		printf("            IRQ:  %xh\n",regs.h.cl);
		}
}

void wake_prog(void)
{
    regs.h.al = 0x4;
    regs.h.ah = int2f_id;
	regs.x.bx = reg_pid;
    int86(0x2f,&regs,&regs);
	if(regs.h.al == 0)
    	printf("        Program Woken\n");
	else
    	printf("        Program Failed to Wake\n");
}

/**
 ** This function will call int 2f function 21h - Open device trying to
 ** allocate the midicomplex device.  
 ** SBOS will fail on this request and return a -1 in ax.
 **/
int open_midicomplex(void)
{
    regs.h.al = 0x21;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
    sregs.es = FP_SEG(midicomplex);
    regs.x.di = FP_OFF(midicomplex);
    int86x(0x2f,&regs,&regs,&sregs);
    if(regs.x.ax == 0)
        {
        printf("        Allocated %s\n",midicomplex);
        return 1;
        }
    else
        {
        printf("        Can't Allocate %s\n",midicomplex);
        return 0;
        }
}

/**
 ** This function will call int 2f function 21h - Open device trying to
 ** allocate the midisimple device.  'MIDISIMPLE' is loaded into es:di
 ** SBOS will respond to this and return a 0 in ax.  The returned software
 ** interrupt (7eh if SBOS is loaded) and handle number will be saved for 
 ** later.
 **/
int open_directcodec(void)
{
    regs.h.al = 0x21;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
    sregs.es = FP_SEG(directcodec);
    regs.x.di = FP_OFF(directcodec);
    int86x(0x2f,&regs,&regs,&sregs);
    if(regs.x.ax == 0)
        {
        printf("        Allocated %s\n",directcodec);
		printf("            BASE: %xh\n",regs.x.bx);
		printf("            DMA:  %xh\n",regs.h.ch);
		printf("            IRQ:  %xh\n",regs.h.cl);
		codec_handle = regs.x.dx;
        return 1;
        }
    else
        {
        printf("        Can't Allocate %s\n",directcodec);
        return 0;
        }
}

/**
 ** This function will call int 2f function 21h - Open device trying to
 ** allocate the midisimple device.  'MIDISIMPLE' is loaded into es:di
 ** SBOS will respond to this and return a 0 in ax.  The returned software
 ** interrupt (7eh if SBOS is loaded) and handle number will be saved for 
 ** later.
 **/
int open_midisimple(void)
{
    regs.h.al = 0x21;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
    sregs.es = FP_SEG(midisimple);
    regs.x.di = FP_OFF(midisimple);
    int86x(0x2f,&regs,&regs,&sregs);
    if(regs.x.ax == 0)
        {
        printf("        Allocated %s\n",midisimple);
        swint  = regs.x.bx;
        synth_handle = regs.x.dx;
        return 1;
        }
    else
        {
        printf("        Can't Allocate %s\n",midisimple);
        return 0;
        }
}

/**
 ** This function will try to play the chord defined in midi_string by calling
 ** the software interrupt (7eh) function 2.  This function, instead of
 ** hardcoding the interrupt number should look at the swint variable and
 ** call it instead.  This way is much simpler.  This will only work if
 ** sbosvector=7e is in the [iwsbos] section in the iw.ini file.  That is
 ** the default, so it shouldn't be a problem
 ** If a bad handle is passed or if the device has not been registered,
 ** EAX will be zero.
 **/
void play_midi(void)
{
    _ES =  FP_SEG(midi_string);
    _EDI = FP_OFF(midi_string);
    _ECX = 7L; // count of bytes
    _DX = synth_handle;
    _EAX = 0x0002L;
    asm int 7eh;
    if(_EAX != 0)
        printf("        Play Failed\n");
    else
        printf("        Play Passed\n");
}

/**
 ** This function calls int 2f with function 22h to close the midi device
 ** opened in function 21h.  The handle must be correct or it will fail AND
 ** one can only open the device once without closing it.  If a bad handle
 ** is passed in or the device was closed without being opened, an error will
 ** be returned.
 **/
void close_midisimple(void)
{
    regs.h.al = 0x22;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
    regs.x.dx = synth_handle;
    int86x(0x2f,&regs,&regs,&sregs);
    if(regs.x.ax == 0)
        printf("        Freed %s\n",midisimple);
    else
        printf("        Can't Free %s\n",midisimple);
}

/**
 ** This function calls int 2f with function 22h to close the midi device
 ** opened in function 21h.  The handle must be correct or it will fail AND
 ** one can only open the device once without closing it.  If a bad handle
 ** is passed in or the device was closed without being opened, an error will
 ** be returned.
 **/
void close_directcodec(void)
{
    regs.h.al = 0x22;
    regs.h.ah = int2f_id;
    regs.x.bx = reg_pid;
    regs.x.dx = codec_handle;
    int86x(0x2f,&regs,&regs,&sregs);
    if(regs.x.ax == 0)
        printf("        Freed %s\n",directcodec);
    else
        printf("        Can't Free %s\n",directcodec);
}

void test_prog(void)
{
    printf("Install ID %d:\n",reg_pid);
    if(get_status() & 0x04)     /* are game functions supported */
        {
		/** Test MIDISIMPLE **/
        open_midisimple();       /** should pass **/
        play_midi();             /** should pass **/
        open_midisimple();       /** should fail **/
        close_midisimple();      /** should pass **/
		play_midi();             /** should fail **/
        close_midisimple();      /** should fail **/

		/** Test MIDICOMPLEX **/
        open_midicomplex();      /** should fail **/

		/** Test DIRECTCODEC **/
        open_directcodec();      /** should pass **/
        open_directcodec();      /** should fail **/
        close_directcodec();     /** should pass **/
        close_directcodec();     /** should fail **/

		/** Test sleep/wake **/
		suspend_synth();
		suspend_synth();         /** fail **/
		get_status();
		wake_prog();
		wake_prog();             /** both pass **/
		get_status();            /** should be back to normal here **/
		suspend_codec();
		suspend_codec();         /** fail **/
		get_status();
		wake_prog();
		wake_prog();             /** both pass **/
		get_status();            /** should be back to normal here **/

		/** Test combination **/
		suspend_synth();
		open_midisimple();       /** should fail **/
		close_midisimple();      /** should fail **/
		wake_prog();
		open_midisimple();
		suspend_synth();         /** should fail **/
		close_midisimple();
		get_status();
        }
}
                        
void main(void)
{
    char far * ptr;
    unsigned long eax,ebx,ecx,edx,esi,edi;
    unsigned short es;
    int numtsrs;

    printf("Searching INT 2F from %X to %X\n",START,END);
    for(int2f_id = START; int2f_id<END; int2f_id++)
        {
        if(test_2f_id())
            {
            if((regs.x.dx == ET) && (regs.x.si == EK)) /** Found an IW TSR **/
                {
                numtsrs = get_num_tsrs();
                numtsrs--; /** make it count the ones that are already there **/
                for(reg_pid = numtsrs;reg_pid>=0; reg_pid--)
					test_prog();
                }
            }
        }
}

