/*$Author:   DCODY  $*/
/*$Date:   27 Jul 1992 12:02:46  $*/
/*$Header:   W:/sccs/mixers/mixerc.c_v   1.3   27 Jul 1992 12:02:46   DCODY  $*/
/*$Log:   W:/sccs/mixers/mixerc.c_v  $
 * 
 *    Rev 1.3   27 Jul 1992 12:02:46   DCODY
 * initialized the 32 bit vectors to 0 so they are placed in the initialized
 * static data segment.
 * 
 *    Rev 1.2   25 Jun 1992 23:49:44   DCODY
 * Simplified the routine by eliminating the static linked and disk
 * resident driver loading.
 * 
 *    Rev 1.1   23 Jun 1992 16:45:12   DCODY
 * PAS2 update
 * 
 *    Rev 1.0   15 Jun 1992 09:41:34   BCRANE
 * Initial revision.
*/
/*$Logfile:   W:/sccs/mixers/mixerc.c_v  $*/
/*$Modtimes$*/

;	/*\
;---|*|----====< MIXERC.C >====----
;---|*|
;---|*| Initialize and setup the access to the mixers, volume, filter, etc
;---|*|
;---|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved
;---|*|
;	\*/

#include <stdio.h>
#include <stdlib.h>
// #include "mixbin.h"              // the actual mixer code
#include "state.h"                  // the state structure

		int  ThePASDMAChannel = 0;	// DMA channel
		int  ThePASIRQChannel = 0;	// IRQ channel

		static int dummyroutine 	   ();

		int (far *MVSetMixerFunction)  () = 0;
		int (far *MVSetVolumeFunction) () = 0;
		int (far *MVSetFilterFunction) () = 0;
		int (far *MVSetCrossChannel)   () = 0;
		int (far *MVGetMixerFunction)  () = 0;
		int (far *MVGetVolumeFunction) () = 0;
		int (far *MVGetFilterFunction) () = 0;
		int (far *MVGetCrossChannel)   () = 0;
		int (far *MVRealSoundSwitch)   () = 0;
		int (far *MVFMSplitSwitch)	   () = 0;

#define STATICDRIVER	0x0000		// The static driver is loaded.
#define DOSDRIVER		0x0001		// The DOS driver is loaded.
// #define DISKDRIVER	0x0002		// The Disk resident driver is loaded.

		// shadow pointer has the active state table pointer

        extern struct MVState far *mvhwShadowPointer;

		// MVMixerHWState allows the pointer to be changed

        struct MVState far *MVMixerHWState(struct MVState far *);

////
////  /*\
////  |*|----====< test code >====----
////  |*|
////  |*| this is test code to be removed
////  |*|
////  \*/
//// int main()
//// {
////
////	// In each of the following calls, MVInitMixerCode will search for
////	// the DOS driver, "MVSOUND.SYS". If found, all succeeding calls to
////	// the mixers will be routed through MVSOUND.SYS. If the DOS driver
////	// is not found, then either the DISK based version, or the static
////	// version will be used. To select the DISK based version, pass a
////	// path to MVInitMixerCode. Any pointer (other than a NULL) will tell
////	// the routine to load the driver from the disk. NOTE: If loading from
////	// the disk fails, then the static driver will be used.
////
////	//
////	// EXAMPLE #1 - The following will attempt to
////	//				load the driver from the disk.
////
////		MVInitMixerCode ( "." );
////
////	//
////	// EXAMPLE #2 - the following will use the
////	//				static built-in driver.
////
////		MVInitMixerCode ( 0 );
//// }
////

;	/*\
;---|*|----====< MVInitMixerCode >====----
;---|*|
;---|*| Load link to the DOS driver, or load the mixer code
;---|*|
;---|*| Entry Conditions:
;---|*| 	char *path is the path to the disk resident driver.
;---|*|
;---|*| Return Value:
;---|*| 	 0, the mixer code is using the static driver.
;---|*| 	 1, the mixer code is using DOS driver.
;---|*|
;	\*/

int MVInitMixerCode()
{
char *p,*p1;
int n,mx,tablelen;
long far *bfp;			// buffer far pointer
long far *tfp;			// table far pointer
long mvver; 			// MVSOUND.SYS version #

static int retry = 0;	// reentry flag. We will only execute once
static int retcode = 0;

	// exit if this code has already been executed

		if (retry++)
			return(retcode);

    // flush some variables

		mx = 0;

		_asm {

			; fill in the functions in case MVSOUND.SYS is not loaded

			mov 	bx, offset dummyroutine
			mov 	word ptr [MVSetMixerFunction+0],bx
            mov     word ptr [MVSetMixerFunction+2],cs

			mov 	word ptr [MVSetVolumeFunction+0],bx
            mov     word ptr [MVSetVolumeFunction+2],cs

			mov 	word ptr [MVSetFilterFunction+0],bx
            mov     word ptr [MVSetFilterFunction+2],cs

			mov 	word ptr [MVSetCrossChannel+0],bx
            mov     word ptr [MVSetCrossChannel+2],cs

			mov 	word ptr [MVGetMixerFunction+0],bx
            mov     word ptr [MVGetMixerFunction+2],cs

			mov 	word ptr [MVGetVolumeFunction+0],bx
            mov     word ptr [MVGetVolumeFunction+2],cs

			mov 	word ptr [MVGetFilterFunction+0],bx
            mov     word ptr [MVGetFilterFunction+2],cs

			mov 	word ptr [MVGetCrossChannel+0],bx
            mov     word ptr [MVGetCrossChannel+2],cs

			mov 	word ptr [MVRealSoundSwitch+0],bx
            mov     word ptr [MVRealSoundSwitch+2],cs

			mov 	word ptr [MVFMSplitSwitch+0],bx
			mov 	word ptr [MVFMSplitSwitch+2],cs

        ; deterine if the DOS driver is loaded

			mov 	ax,0xbc00				; function 0 is for ID
			mov 	bx,0x3f3f
			sub 	cx,cx
			sub 	dx,dx
			int 	2fh 					; go get it...
			xor 	bx,cx					; combine all registers
			xor 	bx,dx
			cmp 	bx,0x4d56				; to form 'MV'
			jnz 	mvininodosdriver

			mov 	ax,0xbc01				; get the version
			int 	2fh

			mov 	word ptr [mvver+0],bx	; save the version
			mov 	word ptr [mvver+2],cx

		; the DOS driver is loaded, use it's vectors, data, etc

			sub 	cx,cx					; comes back 0 or the entry length
			mov 	ax,0xbc03				; get the vector table
			int 	0x2f					; from the DOS driver

			mov 	word ptr [tfp+0],bx 	; save the function pointer offset
			mov 	word ptr [tfp+2],dx 	; and segment
			mov 	[tablelen],cx

			mov 	ax,0bc04h				; get the DMA & IRQ
			int 	0x2f					; from the DOS driver

			mov 	byte ptr ThePASDMAChannel,bl	; DMA channel
			mov 	byte ptr ThePASIRQChannel,cl	; IRQ channel

          mvininodosdriver:

		}

	// we have the pointer to some table. Now, load each function
	// pointer into the individual far pointers.

		if (mvver > 0x30313032) 		// ASCII version 0102
			retcode = DOSDRIVER;		// indicate the DOS driver is loaded

	// set the first 4 (1st rev of MVSOUND just had 4 functions)

        (long) MVSetMixerFunction  = (long) *tfp++;
		(long) MVSetVolumeFunction = (long) *tfp++;
		(long) MVSetFilterFunction = (long) *tfp++;
		(long) MVSetCrossChannel   = (long) *tfp++;

	// set the next entries (later revs of MVSOUND had 10 functions)

		if (tablelen > 4) {
			(long) MVGetMixerFunction  = (long) *tfp++;
			(long) MVGetVolumeFunction = (long) *tfp++;
			(long) MVGetFilterFunction = (long) *tfp++;
			(long) MVGetCrossChannel   = (long) *tfp++;
			(long) MVRealSoundSwitch   = (long) *tfp++;
			(long) MVFMSplitSwitch	   = (long) *tfp;
		}

	// return the code

	return retcode;
}


;	/*\
;---|*|----====< MVMixerHWState >====----
;---|*|
;---|*| fetch and/or load a pointer to the state table.
;---|*|
;---|*| Entry Conditions:
;---|*| 	MVState far *  --  pointer to another table. If NULL (0),
;---|*| 					   the current pointer is only returned. Only
;---|*| 					   non-zero table pointers will be loaded.
;---|*| Return Value:
;---|*| 	 Returns the pointer to the table currently
;---|*| 	 used by the mixer code.
;---|*|
;	\*/

struct MVState far *MVMixerHWState(tbl)
	struct MVState far *tbl;
{

	// if the shadow pointer is not initialized, then do it...

		if (!mvhwShadowPointer)
			MVInitStatePtr();

	// In the first rev of software the static driver could receive
	// the caller's state table. Now that the static driver is gone,
	// we don't want to mess with...

		//	if (tbl)
		//		mvhwShadowPointer = tbl;

	// return the active table

		return (tbl);
}


;	/*\
;---|*|----====< static dummyroutine >====----
;---|*|
;---|*| This routine no-ops out the function calls in case MVSOUND.SYS
;---|*| is not loaded.
;---|*|
;---|*| Entry Conditions:
;---|*| 	none
;---|*|
;---|*| Return Value:
;---|*| 	 0
;---|*|
;	\*/

static int dummyroutine ()
{
	return 0;
}

;	/*\
;---|*| End of MIXERC.C
;	\*/


