; /*\ ;---|*|----====< MIXERC.C >====---- ;---|*| ;---|*| Initialize and setup the access to the mixers, volume, filter, etc ;---|*| ;---|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved ;---|*| ; \*/ #include #include #include "mixbin.h" // the actual mixer code #include "state.h" // the state structure ; /*\ ;---|*|---------------====< Programming Caveat >====--------------\ ;---|*| | ;---|*| This code is provided for documentation ONLY. It has been | ;---|*| replaced by MIXERC.C. Please use the newer body of code | ;---|*| for all your development, thus avoiding hardware depend- | ;---|*| encies. | ;---|*| | ;---|*|---------------====< Programming Caveat >====--------------/ ; \*/ 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. extern struct MVState far *mvhwShadowPointer; static struct MVState far *(far *MVMixerHWStateFunction)() = 0; 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. ;---|*| 2, the mixer code is using Disk resident driver. ;---|*| ; \*/ int MVInitMixerCode(path) char *path; { 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 { ; fixup the linked in code to be on a paragraph alignment push es push di push si mov bx,ds mov es,bx mov di,offset code_block ; get the start of the block mov si,17 ; # of leading zeros in code_block add si,di ; si points to the start and di,0xfff0 ; knock out the low nibble add di,0x10 ; move back up to a starting place sbb ax,ax ; overflow carries into the segment and ax,1000h add bx,ax mov ax,di ; calculate a new segment:offset mov cl,4 shr ax,cl add bx,ax ; address is bx:0000 mov cx,2048/2 cld rep movsw mov [bfp+0],cx ; save the new offset mov [bfp+2],bx ; save the new segment call far ptr [bfp] ; go get the table pointer. mov [tfp+0],ax ; save the function table ptr mov [tfp+2],dx mov byte ptr ThePASDMAChannel,bl ; save the DMA channel mov byte ptr ThePASIRQChannel,cl ; save the IRQ channel pop si pop di pop es } _asm { ; for small model, we have to update the segments 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: } // if the above code did not find the DOS driver, we will attempt to // load the DOS mixer driver program located in the caller's path. if (retcode != DOSDRIVER) { // no dos driver try the disk version if (path) { // if there is a path, try to load it // copy the path to working storage p1 = p = &code_block[2048-64];// build it at the end of buffer while ((*p++ = *path++) != 0); // try to append a '\' to the path if (*(p-2) != '\\') *(p-1) = '\\'; // move the file name n = 0; while ((*p++ = "mixer.drv"[n++]) != 0) ; // attempt to open the file and read in the driver _asm { mov dx,[p1] ; ds:dx points to the file mov ax,0x3d00 ; open a file for reading int 0x21 jc nofilehere ; skip out if not found push ds ; save... lds dx,bfp ; get the storage pointer mov bx,ax mov cx,2048 ; our max size mov ah,0x3f int 0x21 ; load the driver pop ds ; ...restore pushf mov ah,0x3e ; close the file int 0x21 popf ; get the success flag jc nofilehere call far ptr bfp ; init the code mov [tfp+0],ax ; save the function table ptr mov [tfp+2],dx mov byte ptr ThePASDMAChannel,bl ; DMA channel mov byte ptr ThePASIRQChannel,cl ; IRQ channel mov retcode,DISKDRIVER ; the disk driver is loaded. nofilehere: } } } /* check the static driver to see if we can change the state pointer */ _asm { push es les bx,bfp inc bx inc bx cmp es:[bx+1],0 jz nostatefunc ; no, skip the pointer save mov [MVMixerHWStateFunction+0],bx ; pointer to state table fetch mov [MVMixerHWStateFunction+2],es ; or set function ; nostatefunc: pop es } // 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; } // setup the local drivers state table pointer if (retcode != DOSDRIVER) MVMixerHWState(mvhwShadowPointer); // 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 (MVMixerHWStateFunction) { // if there is a function, call it _asm { mov ax,[tbl+0] mov dx,[tbl+2] call far ptr [MVMixerHWStateFunction] mov [tbl+0],ax mov [tbl+2],dx } } 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 \*/