; ; File: SndPrimitives.a ; ; Contains: Low-level routines for the control of sound dependent hardware. ; ; Written by: Dave Wong, Andy Gong, Helder Ramalho ; ; Copyright: © 1991-1993 by Apple Computer, Inc. All rights reserved. ; ; This file is used in these builds: ROM ; ; Change History (most recent first): ; ; 12/21/93 ged Rolled back everything from the previous checkin except minimal ; support for Yeager and Blackbird sound primitives. Additional ; Blackbird sound primitives will be rolled in when ready. ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines. ; 10/1/93 JDR Rolled in the InstallSndPrimitives routine from Reality patches. ; System Software has SndPrimitives patches that patch certain ; machines that were never rolled into the ROM. Why wasn't any of ; this code rolled in previously? Hope it works! I did roll in ; TIMInputSelect patch. I think ElsieInputSelect might still be ; wrong. ; 8/20/93 chp Sound interrupt primitives all referred to the ASC, which was a ; misnomer. This has been updated to reflect the appropriate level ; of abstraction in InterruptHandlers.a. ; 8/4/93 JDR SoundPriv.a was changed to SoundPrivate.a ; 5/25/93 joe Added vector table & stub routines for PDM. ; 1/14/93 PN Add SndCntlMacIIsi table for Macsi sound init. ; 12/5/92 SWC Added routines to do sound hardware initialization for ; StartInit. Added a table for DJMEMC-based machines because the ; sound init code does more stuff than the standard Batman code. ; Moved InitSndHW, InitSndNoRAM, InitSoundHW here from ; StartInit.a. ; 12/3/92 EH Zero out entries for DFAC-related routines in the Blackbird ; table (for now). ; 12/01/92 HY Changed default value for DFAC initialization for LCR/LCII. ; 12/1/92 EH Added table for Blackbird. ; 11/30/92 SWC Updated to latest Horror. Added in build conditionals. ; 11/9/92 ag Added save of d2 in baselevel inputselect routine. The routine ; was trashing d2. ; 11/6/92 rab Roll in Horror changes. Comments follow: ; 10/15/92 NJV Changed the Vail InputSelect and SetVol primitives so that the ; UserVolume variable is treated correctly with the new scheme of ; Volume control on Vail. ; 9/10/92 NJV Added new SndCntlVail table that controls volume via DFAC rather ; than the standard ASIC volume control. Added VailInputSelect, ; changed SonoraInputSelect to call on to InputSelect rather than ; SonoraNewInputSelect. ; 7/14/92 ag Removed redundent routine adjustautosleep. ; 7/13/92 ag Added DartPlayThru and DartQueryInput routines. Added changes to ; disable playthru if input select is internal mic otherwise we ; get HORRible feedback. ; 6/29/92 GMR Added modem sound support for DB-Lite. ; 6/3/92 NJV Changed SonoraInputSelect to enable Sonora to Play and Record ; simultaneously. ; 6/03/92 HY Make LC use same sound vector table as Apollo. Add label SndCntlElsie. ; 5/19/92 ag Fixed bugs with DartInputSelect. ; 5/8/92 djw Modify DartDFACInit to not use low mem to get DecoderInfo ptr ; 5/7/92 ag Added a new table for dartanian. Moved all the tables to the end ; due to an assembler problem ?? ; 05/06/92 jmp Just added a comment to the EgretDFACInit routine; no code was ; changed. ; 9/9/92 RB Added a Sound control vector table for LC. (Same as for Classic ; II (Apollo)). ; 5/21/92 RB Making changes for Cyclone. Change history is below: some ; comments may be duplicated due to the Pandora/Horror history. ; 5/13/92 KW (djw,H14) Modify DartDFACInit to not use low ; mem to get DecoderInfo ptr (ag,H13) Added a new table for ; dartanian. Moved all the tables to the end due to an assembler ; problem ?? (jmp,H12) Just added a comment to the EgretDFACInit ; routine; no code was changed. 4/16/92 KW (SWC, H11) ; Modified the DFAC send routine for DBLite to send the DFAC ; command byte and a byte specifying the input source. ; (NJV,H10)Changed SonoraDFACInit to reverse the order of bits ; it's sending, so that equate can be in DFAC order 03/23/92 ; jmp (jmp,H9) Moved the SonoraDFACInit and SonoraInputSelect ; routines so that the Horror ROM map lines up with Zydeco’s. ; 03/22/92 jmp Put back . 3/19/92 FU Rolled back changes ; in . 3/18/92 FU (NJV,H8) Added SonoraDFACInit, ; SonoraInputSelect, and updated table for Sonora-based machines. ; 02/21/92 jmp Added a fake SoundPrimitives table for ; Cyclone. 02/07/92 jmp (jmp,H7/BG,Z16) Changed ; EclipseInputSelect to call ReGenSoundInt after the final ; VIA2[vBufB] reference is made. Added ReGenSoundInt. Also, moved ; the Sonora table to the end of the file to make the ; TERROR/Zydeco ROM map line up with HORROR’s. 1/15/92 RP ; Added Cyclone sound stub (that will never work). 01/13/92 ; jmp (SWC,H6) Found it's better if A0 points to a parameter block ; before calling _PMgrOp in DBLiteDFACSend. ; <1> 5/17/92 kc first checked in ; 5/2/92 kc Roll in Horror. Comments follow: ; 4/13/92 SWC Modified the DFAC send routine for DBLite to send the DFAC ; command byte and a byte specifying the input source. ; 3/25/92 NJV Changed SonoraDFACInit to reverse the order of bits it's ; sending, so that equate can be in DFAC order ; 03/23/92 jmp Moved the SonoraDFACInit and SonoraInputSelect routines so that ; the Horror ROM map lines up with Zydeco’s. ; 3/12/92 NJV Added SonoraDFACInit, SonoraInputSelect, and updated table for ; Sonora-based machines. ; 01/27/92 jmp (BG,Z16) Changed EclipseInputSelect to call ReGenSoundInt after ; the final VIA2[vBufB] reference is made. Added ReGenSoundInt. ; Also, moved the Sonora table to the end of the file to make the ; TERROR/Zydeco ROM map line up with HORROR’s. ;
1/6/92 SWC Found it's better if A0 points to a parameter block before ; calling _PMgrOp in DBLiteDFACSend. ;
12/16/91 HJR Add primitives for Dartanian. ;

12/4/91 CCH Added sound information for Vail and Carnation. ;

8/6/91 SWC Oops! Got snagged by a MOVEQ value out of range... ;

8/6/91 SWC Added DB-Lite input select routine to disable auto sleep when a ; sound source is enabled. ; <1> 12/29/91 RB first checked in ; ——————————————————————————————————————————————————————————————————————————————————————— ; Pre-HORROR ROM comments begin here. ; ——————————————————————————————————————————————————————————————————————————————————————— ; <15> 7/8/91 djw Take out debugger statement that I left in. ; <14> 7/8/91 djw Undid and made spike and eclipse not force AGC on in the ; input select. ; <13> 6/27/91 HJR & AG, AGCInputSelect still needs to be used in Spike and ; Eclipses InputSelect. ; <12> 6/25/91 ag (djw) Fix bug in EclipseInputSelect were you can never change ; the input source. ; <11> 6/24/91 ag added code to disable auto sleep when a sound source is enabled. ; Changed AGCcontrol to use AGCoff instead of TCAoff. ; <10> 6/24/91 HJR Added appropriate WITH statements since pmCommand and Sleepq are ; now records. ; <9> 6/13/91 djw Disable interrupts around critical code sections. Make ; InputSelect routine return old source. ; <8> 5/31/91 djw Fix bug in DB-Lite DFAC initialization due to value change ; (can't use MOVEQ) ; <7> 5/23/91 HJR Added include to PowerPrivEqu.a. ; <6> 5/10/91 djw Add new hardware recommondations for DFAC settings to lessen ; noise leakage. Roll in SWC's DBLite additions plus code ; optimizations. Changed all "jsrTBL" macro calls to not need to ; pass a register in. Added padding to end of file, added new ; Eclipse input select routine for new VIA bits MUX. ; <5> 3/18/91 djw Changed TIM to use same routines as Spike for EVT3 hardware. ; Added Apollo support. Added new sound primitive routines and ; fixed bugs in InputSelect for Eclipse. ; <4> 2/18/91 djw Have Eclipse DFAC routines always leave AGC enabled. ; <3> 2/18/91 djw Correct relative table offsets for Spike and Eclipse. Corrected ; DFAC bit on TIM from 6 to 5 (thanks to KIP). Improved DFAC TIM ; and VIA2 routines to init clock to known state. ; <2> 2/15/91 djw Add Scott Smyers changes to DFAC Init routines: use DecoderInfo ; record and clean up register use and equates. Make tables ; addresses relative, will create separate entry points for ; Eclipse, Elsie, and Erickson DFAC Init. Re-write Egret/DFAC ; routines. ; <1> 1/24/91 HJR First check in. ; print off LOAD 'StandardEqu.d' include 'HardwarePrivateEqu.a' include 'SoundPrivate.a' include 'UniversalEqu.a' include 'PowerPrivEqu.a' include 'EgretEqu.a' include 'IOPrimitiveEqu.a' include 'SysPrivateEqu.a' ; include 'MMUEqu.a' include 'BootEqu.a' ; needs MMUEqu.a print on print nomdir machine mc68020 ;_________________________________________________________________________________________ ; Install Sound Primitives routines into ExpandMem vector InstallSndPrimitives proc export WITH DecoderInfo,DecoderKinds,ProductInfo,SoundIOHeader,ExpandMemRec WITH SleepqRec,pmCommandRec,PmgrRec IMPORT ClearSoundInt ; InterruptHandlers.a IMPORT DisableSoundInts ; InterruptHandlers.a IMPORT EnableSoundInts ; InterruptHandlers.a IMPORT GetHardwareInfo ; Universal.a IMPORT RDXBYTE ; USTPram.a EXPORT InitSndHW, InitSndNoRAM ; Convert ROM sound primitive offset table into a RAM pointer table. movea.l UnivInfoPtr,a1 ; a1 = ptr to productinfo record move.l ProductInfo.SndControlPtr(a1),d0 ; get offset to sound vector tbl adda.l d0,a1 ; a1 = ptr to ROM tbl moveq.l #0,d0 ; clear d0 move.w SndTblLength(a1),d0 ; d0 = number of entries in table asl.l #2,d0 ; convert long entries to byte count addq.l #SoundIOHeaderSize,d0 ; size of global header records _NewPtr ,sys,clear ; alloc storage adda.l #SoundIOHeaderSize,a0 ; inc past global header move.l a0,([Expandmem],\ ExpandMemRec.emSndPrimitives) ; set the expandmem pointer move.b #sndAGCOff,UserAGC(a0) ; init AGC off as default ; Convert the offset values in the original table to long addresses in the RAM-based ; table. a0 = ptr to new RAM-based tbl, a1 = ptr to old ROM table move.w SndTblLength(a1),d0 ; get number of entries in table subq.w #1,d0 ; adjust for dbra move.l a1,d1 ; d1 = address of ROM/RAM table @Loop move.l (a1)+,(a0) ; get routine offset add.l d1,(a0)+ ; add ROM/RAM table address to convert to 32 bit address dbra d0,@Loop moveq.l #1,d0 ; default all cpu's with AGC on jsrTBL sndAGCcontrol rts ;_________________________________________________________________________________________ ; Sound primitives vector table ; ; Tables pointed to by the universal ProductInfo record (SndControlPtr) ; for low level sound routines dependent on the hardware. There should ; be a table for each supported productinfo. ; align 4 IF hasVISADecoder THEN Export SndCntlClassicII,SndCntlLC dc.w 0 ; flags dc.w (SndCntlClassicIIEnd-SndCntlClassicII)/4 ; number of entries SndCntlLC ; SndCntlClassicII dc.l ElsieDFACInit-SndCntlClassicII dc.l EgretDFACSend-SndCntlClassicII dc.l ASCSetVol-SndCntlClassicII dc.l EnableSoundInts-SndCntlClassicII dc.l DisableSoundInts-SndCntlClassicII dc.l ClearSoundInt-SndCntlClassicII dc.l ElsieInputSelect-SndCntlClassicII dc.l QueryInput-SndCntlClassicII dc.l ByPassControl-SndCntlClassicII dc.l PlayThruVol-SndCntlClassicII dc.l AGCControl-SndCntlClassicII dc.l ASCInitSoundHW-SndCntlClassicII ; SndCntlClassicIIEnd ENDIF IF hasMDU THEN Export SndCntlMacIIsi ; PN.start dc.w 0 ; flags PN dc.w (SndCntlMacIIsiEnd-SndCntlMacIIsi)/4 ; number of entries PN SndCntlMacIIsi dc.l ElsieDFACInit-SndCntlMacIIsi dc.l EgretDFACSend-SndCntlMacIIsi dc.l ASCSetVol-SndCntlMacIIsi dc.l EnableSoundInts-SndCntlMacIIsi dc.l DisableSoundInts-SndCntlMacIIsi dc.l ClearSoundInt-SndCntlMacIIsi dc.l InputSelect-SndCntlMacIIsi dc.l QueryInput-SndCntlMacIIsi dc.l ByPassControl-SndCntlMacIIsi dc.l PlayThruVol-SndCntlMacIIsi dc.l AGCControl-SndCntlMacIIsi dc.l ASCInitSoundHW-SndCntlMacIIsi ; PN.end SndCntlMacIIsiEnd ENDIF IF hasOrwell THEN Export SndCntlQuadra900 dc.w 0 ; flags dc.w (SndCntlQuadra900End-SndCntlQuadra900)/4 ; number of entries SndCntlQuadra900 SndCntlQuadra950 dc.l EclipseDFACInit-SndCntlQuadra900 dc.l EgretDFACSend-SndCntlQuadra900 ; dc.l ASCSetVol-SndCntlQuadra900 dc.l EnableSoundInts-SndCntlQuadra900 dc.l DisableSoundInts-SndCntlQuadra900 dc.l ClearSoundInt-SndCntlQuadra900 dc.l EclipseInputSelect-SndCntlQuadra900 ; dc.l QueryInput-SndCntlQuadra900 dc.l ByPassControl-SndCntlQuadra900 dc.l PlayThruVol-SndCntlQuadra900 dc.l AGCControl-SndCntlQuadra900 dc.l BatmanInitSoundHW-SndCntlQuadra900 SndCntlQuadra900End Export SndCntlQuadra700 dc.w 0 ; flags dc.w (SndCntlQuadra700End-SndCntlQuadra700)/4 ; number of entries SndCntlQuadra700 dc.l SpikeDFACInit-SndCntlQuadra700 dc.l VIA2DFACSend-SndCntlQuadra700 dc.l ASCSetVol-SndCntlQuadra700 dc.l EnableSoundInts-SndCntlQuadra700 dc.l DisableSoundInts-SndCntlQuadra700 dc.l ClearSoundInt-SndCntlQuadra700 dc.l InputSelect-SndCntlQuadra700 ; dc.l QueryInput-SndCntlQuadra700 dc.l ByPassControl-SndCntlQuadra700 dc.l PlayThruVol-SndCntlQuadra700 dc.l AGCControl-SndCntlQuadra700 dc.l BatmanInitSoundHW-SndCntlQuadra700 ; SndCntlQuadra700End ENDIF IF hasJaws THEN Export SndCntlPB170 dc.w 0 ; flags dc.w (SndCntlPB170End-SndCntlPB170)/4 ; number of entries SndCntlPB170 dc.l TimDFACInit-SndCntlPB170 dc.l VIA2DFACSend-SndCntlPB170 dc.l TimPlayBackVol-SndCntlPB170 dc.l EnableSoundInts-SndCntlPB170 dc.l DisableSoundInts-SndCntlPB170 dc.l ClearSoundInt-SndCntlPB170 dc.l TIMInputSelect-SndCntlPB170 ; dc.l QueryInput-SndCntlPB170 dc.l ByPassControl-SndCntlPB170 dc.l PlayThruVol-SndCntlPB170 dc.l AGCControl-SndCntlPB170 dc.l JawsInitSoundHW-SndCntlPB170 ; SndCntlPB170End ENDIF IF hasNiagra THEN Export SndCntlPB180 dc.w 0 ; flags dc.w (SndCntlPB180End-SndCntlPB180)/4 ; number of entries SndCntlPB180 ; dc.l DartDFACInit-SndCntlPB180 dc.l VIA2DFACSend-SndCntlPB180 dc.l TimPlayBackVol-SndCntlPB180 dc.l EnableSoundInts-SndCntlPB180 dc.l DisableSoundInts-SndCntlPB180 dc.l ClearSoundInt-SndCntlPB180 dc.l DartInputSelect-SndCntlPB180 ; dc.l DartQueryInput-SndCntlPB180 ; dc.l ByPassControl-SndCntlPB180 dc.l DartPlayThruVol-SndCntlPB180 ; dc.l AGCControl-SndCntlPB180 dc.l NiagraInitSoundHW-SndCntlPB180 ; SndCntlPB180End ENDIF IF hasMSC THEN Export SndCntlPBDuo210 dc.w 0 ; flags dc.w (SndCntlPBDuo210End-SndCntlPBDuo210)/4 ; number of entries SndCntlPBDuo210 dc.l DBLiteDFACInit-SndCntlPBDuo210 dc.l DBLiteDFACSend-SndCntlPBDuo210 dc.l DBLiteSetVol-SndCntlPBDuo210 ; dc.l EnableSoundInts-SndCntlPBDuo210 dc.l DisableSoundInts-SndCntlPBDuo210 dc.l ClearSoundInt-SndCntlPBDuo210 dc.l DBInputSelect-SndCntlPBDuo210 ;

dc.l QueryInput-SndCntlPBDuo210 dc.l ByPassControl-SndCntlPBDuo210 dc.l PlayThruVol-SndCntlPBDuo210 dc.l AGCControl-SndCntlPBDuo210 dc.l ASCInitSoundHW-SndCntlPBDuo210 ; SndCntlPBDuo210End ; Export SndCntlYeager ; dc.w 0 ; flags dc.w (SndCntlYeagerEnd-SndCntlYeager)/4 ; number of entries SndCntlYeager dc.l DBLiteDFACInit-SndCntlYeager ; (sndDFACInit) dc.l DBLiteDFACSend-SndCntlYeager ; (sndDFACSend) dc.l DBLiteSetVol-SndCntlYeager ; (sndPlaybackVol) dc.l EnableSoundInts-SndCntlYeager ; (sndEnableInt) dc.l DisableSoundInts-SndCntlYeager ; (sndDisableInt) dc.l ClearSoundInt-SndCntlYeager ; (sndClearInt) dc.l DBInputSelect-SndCntlYeager ; (sndInputSelect) dc.l QueryInput-SndCntlYeager ; (sndInputSource) dc.l ByPassControl-SndCntlYeager ; (sndAuxByPass) dc.l PlayThruVol-SndCntlYeager ; (sndPlayThruVol) dc.l AGCControl-SndCntlYeager ; (sndAGCcontrol) dc.l ASCInitSoundHW-SndCntlYeager ; (sndInitSoundHW) dc.l DoNothing-SndCntlYeager ; (sndInitGlobals) dc.l DoNothing-SndCntlYeager ; (sndModemSound) dc.l DoNothing-SndCntlYeager ; (sndModemSndVol) dc.l DoNothing-SndCntlYeager ; (sndGetSmplRate) dc.l DoNothing-SndCntlYeager ; (sndSetSmplRate) dc.l DoNothing-SndCntlYeager ; (sndGetInputGain) dc.l DoNothing-SndCntlYeager ; (sndSetInputGain) dc.l DoNothing-SndCntlYeager ; (sndPlayThruCntl) dc.l DoNothing-SndCntlYeager ; (sndSoundHWCntl) dc.l DoNothing-SndCntlYeager ; (sndSoundHWState) dc.l DoNothing-SndCntlYeager ; (sndVirtualHWHook) SndCntlYeagerEnd ; ENDIF IF hasDJMEMC THEN EXPORT SndCntlQuadra800 dc.w 0 ; flags dc.w (SndCntlQuadra800End-SndCntlQuadra800)/4; number of entries SndCntlQuadra800 dc.l SpikeDFACInit-SndCntlQuadra800 dc.l VIA2DFACSend-SndCntlQuadra800 dc.l ASCSetVol-SndCntlQuadra800 dc.l EnableSoundInts-SndCntlQuadra800 dc.l DisableSoundInts-SndCntlQuadra800 dc.l ClearSoundInt-SndCntlQuadra800 dc.l InputSelect-SndCntlQuadra800 dc.l QueryInput-SndCntlQuadra800 dc.l ByPassControl-SndCntlQuadra800 dc.l PlayThruVol-SndCntlQuadra800 dc.l AGCControl-SndCntlQuadra800 dc.l DJMEMCInitSoundHW-SndCntlQuadra800 ; SndCntlQuadra800End ENDIF IF hasPratt THEN Export SndCntlBlackbird dc.w 0 ; flags (SuperMario style table) dc.w (SndCntlBlackEnd-SndCntlBlackbird)/4 ; number of entries SndCntlBlackbird dc.l DoNothingViaA6-SndCntlBlackbird ; (sndDFACInit) dc.l DoNothing-SndCntlBlackbird ; (sndDFACSend) dc.l ASCSetVol-SndCntlBlackbird ; (sndPlaybackVol) dc.l EnableSoundInts-SndCntlBlackbird ; (sndEnableInt) dc.l DisableSoundInts-SndCntlBlackbird ; (sndDisableInt) dc.l ClearSoundInt-SndCntlBlackbird ; (sndClearInt) dc.l DoNothing-SndCntlBlackbird ; (sndInputSelect) dc.l DoNothing-SndCntlBlackbird ; (sndInputSource) dc.l DoNothing-SndCntlBlackbird ; (sndAuxByPass) dc.l DoNothing-SndCntlBlackbird ; (sndPlayThruVol) dc.l DoNothing-SndCntlBlackbird ; (sndAGCcontrol) dc.l WhitneyInitSoundHW-SndCntlBlackbird ; (sndInitSoundHW) dc.l DoNothing-SndCntlBlackbird ; (dontUse1) dc.l DoNothing-SndCntlBlackbird ; (dontUse2) dc.l DoNothing-SndCntlBlackbird ; (dontUse3) dc.l DoNothing-SndCntlBlackbird ; (sndInitSoundHW2) dc.l DoNothing-SndCntlBlackbird ; (sndInitGlobals) dc.l DoNothing-SndCntlBlackbird ; (sndModemSound) dc.l DoNothing-SndCntlBlackbird ; (sndModemSndVol) dc.l DoNothing-SndCntlBlackbird ; (sndGetSmplRate) dc.l DoNothing-SndCntlBlackbird ; (sndSetSmplRate) dc.l DoNothing-SndCntlBlackbird ; (sndGetInputGain) dc.l DoNothing-SndCntlBlackbird ; (sndSetInputGain) dc.l DoNothing-SndCntlBlackbird ; (sndPlayThruCntl) dc.l DoNothing-SndCntlBlackbird ; (sndSoundHWCntl) dc.l DoNothing-SndCntlBlackbird ; (sndSoundHWState) dc.l DoNothing-SndCntlBlackbird ; (sndVirtualHWHook) SndCntlBlackEnd ENDIF IF hasSonora THEN Export SndCntlSonora dc.w 0 ; flags dc.w (SndCntlSonoraEnd-SndCntlSonora)/4 ; number of entries SndCntlSonora dc.l SonoraDFACInit-SndCntlSonora dc.l EgretDFACSend-SndCntlSonora dc.l ASCSetVol-SndCntlSonora dc.l EnableSoundInts-SndCntlSonora dc.l DisableSoundInts-SndCntlSonora dc.l ClearSoundInt-SndCntlSonora dc.l SonoraInputSelect-SndCntlSonora dc.l QueryInput-SndCntlSonora dc.l ByPassControl-SndCntlSonora dc.l PlayThruVol-SndCntlSonora dc.l AGCControl-SndCntlSonora dc.l BatmanInitSoundHW-SndCntlSonora ; SndCntlSonoraEnd Export SndCntlLCIII dc.w 0 ; flags dc.w (SndCntlLCIIIEnd-SndCntlLCIII)/4 ; number of entries SndCntlLCIII dc.l SonoraDFACInit-SndCntlLCIII dc.l EgretDFACSend-SndCntlLCIII dc.l VailSetVol-SndCntlLCIII dc.l EnableSoundInts-SndCntlLCIII dc.l DisableSoundInts-SndCntlLCIII dc.l ClearSoundInt-SndCntlLCIII dc.l VailInputSelect-SndCntlLCIII dc.l QueryInput-SndCntlLCIII dc.l ByPassControl-SndCntlLCIII dc.l PlayThruVol-SndCntlLCIII dc.l AGCControl-SndCntlLCIII dc.l BatmanInitSoundHW-SndCntlLCIII ; SndCntlLCIIIEnd ENDIF Export SndCntlCyclone dc.w 0 ; flags dc.w (SndCntlCycloneEnd-SndCntlCyclone)/4 ; number of entries SndCntlCyclone dc.l CycloneSndStubNoRam-SndCntlCyclone ; Fake ’em for now. dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub2-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStub1-SndCntlCyclone dc.l CycloneSndStubNoRam-SndCntlCyclone ; SndCntlCycloneEnd Export SndCntlPDM dc.w 0 ; flags dc.w (SndCntlPDMEnd-SndCntlPDM)/4 ; number of entries SndCntlPDM ; Fake 'em dc.l PDMSndStubNoRam-SndCntlPDM ; For machines that need to init DFAC via Egret dc.l PDMSndStub1-SndCntlPDM ; For machines that use Egret to talk to DFAC dc.l PDMSndStub1-SndCntlPDM ; Set Volume dc.l PDMSndStub1-SndCntlPDM ; Enable Sound Interrupts dc.l PDMSndStub1-SndCntlPDM ; Disable Sound Interrupts dc.l PDMSndStub1-SndCntlPDM ; Clear Sound Interrupt(s) dc.l PDMSndStub1-SndCntlPDM ; Input Select dc.l PDMSndStub2-SndCntlPDM ; Query which input device(s) is/are selected dc.l PDMSndStub1-SndCntlPDM ; Enable/Disable Aux Bypass dc.l PDMSndStub1-SndCntlPDM ; Set PlayThru Volume dc.l PDMSndStub1-SndCntlPDM ; Enable/Disable AGC dc.l PDMSndStubNoRam-SndCntlPDM ; InitSoundHW - called by StartInit to set vol SndCntlPDMEnd ;••••••••••••••••••••••••••••••••••• Common Routines •••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; Routine: InitSndHW ; ; Inputs: none ; ; Outputs: none ; ; Trashes: D0-D1 ; ; Function: This routine is meant to be called after lowmem has been setup. ; It calls common RAM-less code in the system to initialize the ; sound hardware. ;—————————————————————————————————————————————————————————————————————————————— InitSndHW movem.l d3-d4/a0-a6,-(sp) movea.l UnivInfoPtr,a1 ; point to the machine's ProductInfo table MOVEA.L A1,A0 adda.l ProductInfo.DecoderInfoPtr(a0),a0 ; and to its DecoderInfo table move.b SdVolume,d0 ; get the sound volume moveq.l #1,d1 ; flag RAM routine origin for InitSoundHW bsr6 InitSoundHW ; initialize the sound hardware (trashes d0-d4/a0-a6) movem.l (sp)+,d3-d4/a0-a6 rts ;—————————————————————————————————————————————————————————————————————————————— ; Routine: InitSndNoRAM ; ; Inputs: A5 - return address ; ; Outputs: none ; ; Trashes: D0-D4, A0-A6 ; ; Function: called by BSR5 to initialize sound hardware without using RAM ;—————————————————————————————————————————————————————————————————————————————— InitSndNoRam move.l a5,d3 ; save return addr in d3 ; Setup necessary registers moveq.l #0,d2 ; decoder unknown bsr6 GetHardwareInfo ; get decoder address (trashes d0-d2/a0-a2/a5/a6) movea.l DecoderInfo.VIA1Addr(a0),a2 ; get VIA1 base addr for PRAM routine ; Call start test utility to read sound volume from pram move.w #$10,d1 ; pram addr of validation byte bsr6 RdXByte ; trashes d0,d2,a0,a3,a4,a5 cmpi.b #$a8,d1 ; is PRAM valid? beq.s @pramValid ; pram is valid moveq.l #5,d1 ; pram invalid - fake a volume level of 5 bra.s @skipRead @pramValid move.w #8,d1 ; pram addr of sound volume bsr6 RdXByte ; trashes d0,d2,a0,a3,a4,a5 @skipRead and.b #%00000111,d1 ; mask volume bits bne.s @nonZeroVol ; a good non-zero volume move.b #5,d1 ; set minimum volume for boot beep @nonZeroVol move.b d1,d4 ; save pram value ; Setup registers again moveq.l #0,d2 ; decoder unknown bsr6 GetHardwareInfo ; get decoder address (trashes d0-d2/a0-a2/a5) move.b d4,d0 ; restore volume moveq.l #0,d1 ; flag RAMless routine origin for InitSoundHW bsr6 InitSoundHW ; init sound (trashes d0-d1/a3/a6) movea.l d3,a5 ; restore return address rts5 ;—————————————————————————————————————————————————————————————————————————————— ; Routine: InitSoundHW ; ; Inputs: D0 - sound volume (0-7) ; A0 - pointer to DecoderInfo table ; A1 - pointer to ProductInfo table ; A6 - return address ; ; Outputs: none ; ; Trashes: D0-D1, A3 ; ; Function: This routine is called by routines which can use RAM, and RAM-less ; routines. It is a central place in the ROM where all sound hardware ; initialization should happen. ;—————————————————————————————————————————————————————————————————————————————— InitSoundHW MOVEA.L A1,A3 ; get the ProductInfo pointer ADDA.L SndControlPtr(A3),A3 ; point to the sound primitives table ADDA.L sndInitSoundHW*4(A3),A3 ; and then to the routine to initialize sound hardware JMP (A3) ; call the routine (will return with RTS6) IF hasASC THEN ;—————————————————————————————————————————————————————————————————————————————— ; ASCSetVol - Set the playback volume on normal ASC/Batman hardware ; ; Set the playback volume using the volume control register on Batman. ; ; Input: d0.b = volume level (0-7) ; Output: none ; ASCSetVol move.l a0,-(sp) movea.l ASCBase,a0 ; get base address of asc/batman lsl.b #5,d0 ; shift volume up to pwm position move.b d0,ascVolControl(a0) ; save it in ASC volume register movea.l (sp)+,a0 rts ;—————————————————————————————————————————————————————————————————————————————— ; ; Routine: ASCInitSoundHW ; ; Inputs: D0 - sound volume (0-7) ; A0 - pointer to machine's DecoderInfo table ; A1 - pointer to machine's ProductInfo table ; A6 - return address ; ; Outputs: none ; ; Trashes: D0,A3 ; ; Function: called by BSR6 from StartInit to set the default volume for ASC ; based machines ;—————————————————————————————————————————————————————————————————————————————— ASCInitSoundHW MOVEA.L ASCAddr(A0),A3 ; point to the base of the ASC ASL.B #5,D0 ; shift the sound volume into the upper 3 bits MOVE.B D0,ascVolControl(A3) ; and set the volume RTS6 ;—————————————————————————————————————————————————————————————————————————————— ; ; Routine: BatmanInitSoundHW ; ; Inputs: D0 - sound volume (0-7) ; A0 - pointer to machine's DecoderInfo table ; A1 - pointer to machine's ProductInfo table ; A6 - return address ; ; Outputs: none ; ; Trashes: D0,A3 ; ; Function: called by BSR6 from StartInit to set the default volume for Batman ; based machines ;—————————————————————————————————————————————————————————————————————————————— BatmanInitSoundHW MOVEA.L ASCAddr(A0),A3 ; point to the base of the ASC ASL.B #5,D0 ; shift the sound volume into the upper 3 bits MOVE.B D0,ascVolControl(A3) ; and set the volume MOVE.W #$7F00,bmLeftScaleA(A3) ; pan channel A full left MOVE.W #$007F,bmLeftScaleB(A3) ; pan channel B full right FinishBatmanInit MOVEQ #1,D0 MOVE.B D0,bmIntControlA(A3) ; mask sound interrupts on channels A & B MOVE.B D0,bmIntControlB(A3) ORI.B #$80,ascFifoControl(A3) ; toggle the clear FIFO bit ANDI.B #$7F,ascFifoControl(A3) MOVE.B #2,ascPlayRecA(A3) ; set to play mode at 22KHz MOVE.B D0,ascMode(A3) ; set to FIFO mode MOVEQ #0,D0 MOVE.B D0,bmFifoControlA(A3) ; force Batman to do mode-change housekeeping MOVE.B D0,bmFifoControlB(A3) MOVE.W #$812F,bmSrcTimeIncrA(A3) ; set sample rate to 22.254.5454 kHz on channels A & B MOVE.W #$812F,bmSrcTimeIncrB(A3) MOVE.W D0,$F10(A3) ; initialize the CD-XA coefficients for channel A MOVE.W #$003C,$F12(A3) MOVE.W #$CC73,$F14(A3) MOVE.W #$C962,$F16(A3) MOVE.W D0,$F30(A3) ; initialize the CD-XA coefficients for channel B MOVE.W #$003C,$F32(A3) MOVE.W #$CC73,$F34(A3) MOVE.W #$C962,$F36(A3) MOVE.B #$80,bmFifoControlA(A3) ; turn on Sample Rate Conversion (SRC) for channels A & B MOVE.B #$80,bmFifoControlB(A3) RTS6 ENDIF ; {hasASC} ;—————————————————————————————————————————————————————————————————————————————— ; InputSelect - Select the sound input source ; ; If we are selecting "none" for the input source, then turn off the volume ; and AGC to prevent any noise leakage. Save the old volume and restore it ; later when a new source is selected. ; ; AGCInputSelect ; On Tim and Spike, sound input does not work unless AGC is enabled. We ; kludge something to always set AGC. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) ; Output: d0.b last source ; AGCInputSelect tst.b d0 ; turning on sound input? beq.s InputSelect ; no - go ahead and turn off sound input or.b #sndAGCOn,d0 ; this fixes buggy hardware InputSelect @saveregs reg d1-d2/a0-a1 ; added d2 to save registers movem.l @saveregs,-(sp) movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints moveq.l #3,d2 ; get selection bits to return and.b DFAClast(a0),d2 ; save for return moveq #(sndSelectMask\ ; AND sndPlayThruMask\ AND sndAGCMask),d1 ; mask off selection, volume, and AGC bits and.b DFAClast(a0),d1 ; in the DFAC register image or.b d0,d1 ; and OR them into DFAC image ; Check for volume and AGC to update in DFAC now that a sound source has been selected. ; If we are disabling input, then zero the volume and disable AGC to prevent noise ; leakage, otherwise set the currently selected volume and AGC levels. tst.b d0 ; are we turning off input? beq.s @send ; yes - set no input and zero volume or.b UserVolume(a0),d1 ; set volume level cmpi.b #sndMicrophone,d0 ; are we selecting the mike input? bne.s @send ; no - do not enable AGC or.b UserAGC(a0),d1 ; set AGC level @send move.b d1,d0 ; d0 = new DFAC value jsrTBL sndDFACSend ; call DFACSend routine thru expandmem move.w (sp)+,sr ; enable ints move.b d2,d0 ; return source bits we replaced movem.l (sp)+,@saveregs rts ;—————————————————————————————————————————————————————————————————————————————— ; QueryInput - return current input source selected ; ; Input: none ; Output: d0.b input source ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) QueryInput move.l a0,-(sp) movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table moveq #~(sndSelectMask-256),d0 ; mask off selection bits and.b DFAClast(a0),d0 ; in the DFAC register image movea.l (sp)+,a0 rts ;—————————————————————————————————————————————————————————————————————————————— ; ByPassControl - enable or disable aux bypass ; ; Input: d0.b = 0 is disable, nonzero is enable ; Output: none ; ByPassControl @saveregs reg d1/a0 movem.l @saveregs,-(sp) movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table moveq.l #sndByPassOff,d1 ; assume bypass off tst.b d0 ; enable or disable bypass beq.s @continue ; was bypass off moveq.l #sndByPassOn,d1 ; set bypass on @continue move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints moveq #sndByPassMask-256,d0 ; mask off bypass control bit and.b DFAClast(a0),d0 ; in the DFAC register image or.b d1,d0 ; d0 = value to send DFAC jsrTBL sndDFACSend ; call DFACSend routine thru expandmem move.w (sp)+,sr ; enable ints movem.l (sp)+,@saveregs rts ;—————————————————————————————————————————————————————————————————————————————— ; PlayThruVol - Set the playthrough volume ; ; If a sound source has not been selected, then save the volume in the globals ; to be updated to DFAC later when the source is selected. Also set playback ; volume for consistancy. ; ; Input: d0.b = volume level (0-7) ; Output: none ; PlayThruVol @saveregs reg d1/a0 movem.l @saveregs,-(sp) movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints asl.b #5,d0 ; shift volume into s5-s7 position move.b d0,UserVolume(a0) ; save user set volume level moveq #(sndSelectMask-256),d1 ; mask off selection bits and.b DFAClast(a0),d1 ; in the DFAC register image beq.s @Done ; no sound source - we are done moveq #sndPlayThruMask,d1 ; mask off volume bits and.b DFAClast(a0),d1 ; in the DFAC register image or.b d1,d0 ; or-in value to send DFAC to set volume jsrTBL sndDFACSend ; call DFACSend routine thru expandmem @Done move.w (sp)+,sr ; enable ints movem.l (sp)+,@saveregs rts ;—————————————————————————————————————————————————————————————————————————————— ; AGCControl - enable or disable AGC ; ; Enable or disable AGC. If no sound source has been selected, then ; save the AGC value and set it whenever the sound source is selected. ; ; Input: d0.b = 0 is disable, nonzero is enable ; Output: none ; AGCControl @saveregs reg d1/a0 movem.l @saveregs,-(sp) movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table moveq.l #sndAGCOff,d1 ; assume AGC off (min gain) tst.b d0 ; enable or disable AGC beq.s @continue ; was disable AGC moveq.l #sndAGCOn,d1 ; enable AGC @continue move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints move.b d1,UserAGC(a0) ; save value moveq #(sndSelectMask-256),d0 ; mask off selection bits and.b DFAClast(a0),d0 ; in the DFAC register image beq.s @Done ; no sound source - we are done moveq #sndAGCMask-256,d0 ; mask off the AGC control bits and.b DFAClast(a0),d0 ; in the DFAC register image or.b d1,d0 ; or-in AGC value to send to DFAC jsrTBL sndDFACSend ; call DFACSend routine thru expandmem @Done move.w (sp)+,sr ; enable ints movem.l (sp)+,@saveregs rts IF hasVISADecoder THEN ;••••••••••••••••••••••••••••••••••••••••• VISA ••••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; ElsieInputSelect - Select the sound input source on Elsie ; ; If we are turning off the source (equivalent to disabling recording), then ; re-establish the playback mode by selecting the Aux source with AGC on and ; playthrough volume set to the maximum. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) ; Output: none ; ; NOTE: System software has a different version of this being patched in ?!?!? ElsieInputSelect cmpi.b #sndMicrophone,d0 ; are we selecting the mike? beq InputSelect ; yes - continue ; In Elsie sound, the playthrough with the auxiliary source is how playback is ; done. If not selecting mike, then enable playback @saveregs reg d1/a0 movem.l @saveregs,-(sp) ; movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table ; moveq #(sndSelectMask\ ; ; AND sndPlayThruMask\ ; AND sndAGCMask),d0 ; mask off selection, volume, and AGC bits ; and.b DFAClast(a0),d0 ; get DFAC register image moveq #sndElsieDFAC-256,d0 ; DFAC playback mode for Elsie sound jsrTBL sndDFACSend ; call DFACSend routine thru expandmem movem.l (sp)+,@saveregs rts ENDIF ; {hasVISADecoder} IF hasEgret THEN ;••••••••••••••••••••••••••••••••••••••••• Egret •••••••••••••••••••••••••••••••••••••••• WITH EgretPB Import SendEgretCmd ;—————————————————————————————————————————————————————————————————————————————— ; EgretDFACInit - send a byte to DFAC using Egret ; ; Use this routine during initialization before traps are enabled. ; ; Input: a6.l = return address ; a0.l = Pointer to Base address table ; ; Output: none ; Destroys: d0-d2/a2-a3 ; Called by: bsr6 ; IF hasSonora THEN SonoraDFACInit moveq #sndSonoraReverseDFAC,d0 ; DFAC data to send for Elsie bra.s EgretDFACInit ENDIF IF hasOrwell THEN EclipseDFACInit moveq #sndEclipseDFAC,d1 ; DFAC data to send for Eclipse bra.s EgretDFACInit ENDIF IF hasVISADecoder THEN ElsieDFACInit move.l #ElsieDFAC,d1 ; DFAC data to send for Elsie **** bra.s EgretDFACInit ENDIF EgretDFACInit movea.l a6,a3 ; save return address move.l #(WrDFAC<<16) | PseudoPkt,d0 ; Send DFAC command moveq #DFACInitLen,d2 ; number of bytes of DFAC data bigbsr6 SendEgretCmd,a2 ; send the command to Egret tst.w d0 ; negative if error jmp (a3) ; return to the caller ;—————————————————————————————————————————————————————————————————————————————— ; EgretDFACSend - send a byte to DFAC using Egret ; ; Use this routine during runtime after traps are enabled. ; ; Input: d0.b = byte to send DFAC (in DFAC order) ; Output: none ; EgretDFACSend @saveregs reg d1-d3/a0-a1 movem.l @saveregs,-(sp) ; work register ; Reverse the order of the bits because Egret shifts them out in reverse order ; to what DFAC is expecting MSB first. move.l d0,d3 ; save DFAC value in DFAC order moveq #0,d1 ; destination moveq #8-1,d2 ; loop count for 8 bits @Loop asr.b #1,d0 ; shift lsb into extend bit roxl.b #1,d1 ; shift extend bit towards msb dbra d2,@Loop ; Build a Parameter block for the default DFAC message suba.w #EgretPbSize,sp ; make room for PB movea.l sp,a0 ; point a0 to pbBuffer move.b #pseudoPkt,pbCmdType(a0) move.b #WrDFAC,pbCmd(a0) move.w #1,pbByteCnt(a0) ; set byte count clr.l pbBufPtr(a0) ; clear unused fields clr.w pbFlags(a0) clr.w pbResult(a0) clr.l pbCompletion(a0) move.b d1,pbParam(a0) ; set byte to send DFAC _EgretDispatch adda.w #EgretPbSize,sp ; discard the parameter block and data buffer bne.s @Done ; some error - do not update image of DFAC ; Update the RAM image of the DFAC register movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table move.b d3,DFAClast(a0) ; update DFAC register image @Done movem.l (sp)+,@saveregs rts ; Return to Caller ENDWITH ; {EgretPB} ENDIF ; {hasEgret} IF hasOrwell THEN ;••••••••••••••••••••••••••••••••••••••••• Orwell ••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; EclipseInputSelect - Select the sound input source on Eclipse ; ; On Eclipse, the sound input source is selected by two bits on VIA2 port B ; register in addition to DFAC. There are four sound input sources on ; Eclipse: Microphone (or none?), RCA jacks, Microphone, and the CD (aux). ; These sources are selected through the VIA2 bits and routed through DFAC. ; ; If we are selecting "none" for the input source, then turn off the volume ; and AGC to prevent any noise leakage. Save the old volume and restore it ; later when a new source is selected. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) ; 3 = RCA jacks ; Output: none ; EclipseInputSelect move.w sr,-(sp) ; djw ori.w #HiIntMask,sr ; djw movem.l d0-d1,-(sp) ; djw move.b ([via2],vBufB),d1 ; read current via values djw and.b #%10110111,d1 ; clear the previous value (bits pb6,pb3) djw andi.w #$ff,d0 ; make a word index or.b EclipseSelectTable(pc,d0.w),d1 ; set new input djw move.b d1,([via2],vBufB) ; set via2 bits bsr.s ReGenSoundInt ; since VIA2 access clear interrupts, fix em BG movem.l (sp)+,d0-d1 ; djw move.w (sp)+,sr ; djw tst.b d0 ; selecting no source? beq InputSelect ; yes - ok to go setup DFAC djw moveq.l #sndMicrophone,d0 ; all sound sources go through DFAC mike input bra InputSelect ; djw EclipseSelectTable dc.b %00000000 ; none (or microphone?) pb6=0, pb3=0 dc.b %01000000 ; microphone pb6=1, pb3=0 dc.b %01001000 ; auxilary (CD) pb6=1, pb3=1 dc.b %00001000 ; RCA jacks pb6=0, pb3=1 ;_______________________________________________________________________ thru next thru next ; ; Routine: ReGenSoundInt ; ; Desc: Since reading VIAx[vBufB] causes interrupts to cleared, ; this re-generates those sound interrupts. ; ; This routine stolen from ; ; {Regatta}Toolbox:SoundMgr:SoundMgrPatch.a ; ;_______________________________________________________________________ interruptControlA EQU $F09 ; interrupt mask registers for Batman interruptControlB EQU $F29 ReGenSoundInt move.l a1,-(sp) ; save A1 so we can play with it movea.l VIA2,a1 ; grab the address of VIA2 cmpa.l #-1,a1 ; check if it's been set up yet beq.s @rts ; exit if not btst.b #ifCB1,vIFR(a1) ; check if we still think there's an interrupt bne.s @rts ; yes, we still have an interrupt - exit movea.l ASCBase,a1 ; point to Batman cmpa.l #-1,a1 ; check if it's been set up yet beq.s @rts ; exit if not move.w sr,-(sp) ; preserve the status register ori.w #$0700,sr ; mask interrupts tst.b interruptControlA(a1) ; channel A interrupt enabled? bne.s @checkB ; BRIF not enabled move.b #1,interruptControlA(a1) ; disable chnl A interrupts nop ; give Batman time to process the disable clr.b interruptControlA(a1) ; clear the interrupt mask to re-generate @checkB tst.b interruptControlB(a1) ; channel B interrupt enabled? bne.s @Done ; interrupt not enabled - done ; To re-generate Batman interrupts, first disable interrupts on both channels, ; then re-enable them. @reGen move.b #1,interruptControlB(a1) ; disable chnl B interrupts nop ; give Batman time to process the disable clr.b interruptControlB(a1) ; clear the interrupt mask to re-generate @Done move.w (sp)+,sr @rts move.l (sp)+,a1 ; restore original value of A1 rts ; ENDIF ; {hasOrwell} IF hasJaws THEN ;••••••••••••••••••••••••••••••••••••••••• Jaws ••••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— thru next djw ; TIMInputSelect - Select the sound input source on Tim ; ; On Tim, the input selection routine in ROM always turns AGC on. Patch ; it out to not force AGC on. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim) ; Output: d0.b last source ; AutoSlpDisable equ $f8 ; Counting semaphor to disable sleep TIMInputSelect @workingReg reg d2/a0-a1 move.w sr,-(sp) ; save the old sr movem.l @workingReg,-(sp) ; save working registers move.l PmgrBase,a1 ; point a1 to globals movea.l ([Expandmem],emSndPrimitives),a0 ; a0 = ptr to vector table ori.w #HiIntMask,sr ; disable ints moveq.l #3,d2 ; get selection bits and.b DFAClast(a0),d2 ; beq.s @currentlyOff ; is a source active ?? @currentlySelected ; sound source currently selected tst.b d0 ; check new state, bne.s @setsource ; if just new source, set the source subq.b #1,AutoSlpDisable(a1) ; ... if turning off source, dec the nosleep semaphore bra.s @setsource @currentlyOff ; sound source currently off tst.b d0 ; check new state, beq.s @setsource ; if new source still off, set the source addq.b #1,AutoSlpDisable(a1) ; ... if turning on source, inc the nosleep semaphore ; bra.s @setsource @setsource movem.l (sp)+,@workingReg ; restore working registers bsr InputSelect ; change the source djw move.w (sp)+,sr ; enable ints rts ;—————————————————————————————————————————————————————————————————————————————— ; TimPlayBackVol - Set the playback volume on Tim ; ; Tim uses the left and right scale registers to control the volume. Volume ; levels 0-7 are table mapped. Also should also set playthrough volume for ; consistancy. ; ; Input: d0.b = volume level (0-7) ; Output: none ; TimPlayBackVol move.l a0,-(sp) andi.w #$ff,d0 ; mask to word index move.b @TimVolumeTable(d0.W),d0 ; index into tbl to get mapped volume value move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints movea.l ASCBase,a0 ; get base address of asc/batman move.b d0,bmLeftScaleA(a0) ; channel A plays out left speaker at this volume move.b #0,bmRightScaleA(a0) ; channel A does not play out of the right speaker at all move.b #0,bmLeftScaleB(a0) ; channel B does not play out of the left speaker at all move.b d0,bmRightScaleB(a0) ; channel B plays out right speaker at this volume move.w (sp)+,sr ; enable ints movea.l (sp)+,a0 rts ; Table of values to jam into the Batman scale registers for each sound volume setting (0..7) @TimVolumeTable dc.b 1, 18, 36, 54, 72, 90, 108, 127 align 4 ENDIF ; {hasJaws} IF hasNiagra THEN ;••••••••••••••••••••••••••••••••••••••••• Niagra ••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; DartQueryInput - return current input source selected ; ; Input: none ; Output: d0.b input source ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Dart) DartQueryInput bsr.s QueryInput ; tst.b d0 ; beq.s @done ; if off, done move.l a0,-(sp) ; save a0 movea.l UnivInfoPtr,a0 ; point to the ProductInfo table, adda.l DecoderInfoPtr(a0),a0 ; then to the DecoderInfo table, movea.l JAWSAddr(a0),a0 ; then to the Niagra base address, adda.l #(NiagraGUR+PontiSndCtl),a0 ; point sound control register move.b #sndSelectAux,d0 ; assume modem sound btst.b #PontiSndMux1,(a0) ; check for modem sound override bne.s @returninput ; if override bit, return current d0 value move.b #sndSelectMike,d0 ; set to mike @returninput move.l (sp)+,a0 ; restore a0 | ; V @done rts ; ;—————————————————————————————————————————————————————————————————————————————— ; DartPlayThruVol - Set the playthrough volume ; ; If a sound source has not been selected, then save the volume in the globals ; to be updated to DFAC later when the source is selected. Also set playback ; volume for consistancy. In Dart's case, playthru is disabled (set to 0) if ; the internal microphone is used. This prevents HORRible feedback. ; ; ; ; Input: d0.b = volume level (0-7) ; Output: none ; DartPlayThruVol @saveregs reg d1/a0 ; get the current source movem.l @saveregs,-(sp) ; save working set of registers move d0,d1 ; use d1 for volume until later bsr.s DartQueryInput ; get the current source cmp.b #sndSelectMike,d0 ; is the mike selected, bne.s @setvol ; if not mike, just set the volume ; get pointer to sound control register movea.l UnivInfoPtr,a0 ; point to the ProductInfo table, adda.l DecoderInfoPtr(a0),a0 ; then to the DecoderInfo table, movea.l JAWSAddr(a0),a0 ; then to the Niagra base address, adda.l #(NiagraGUR+PontiSndCtl),a0 ; point sound control register ; check for internal mike btst.b #PontiSndIntMic,(a0) ; check for internal microphone operation beq.s @setvol ; if external microphone, allow playthru move.b #0,d1 ; ... else set playthru to off @setvol move.b d1,d0 ; move volume back to d0 movem.l (sp)+,@saveregs ; restore working set bra PlayThruVol ; set playthru volume ;—————————————————————————————————————————————————————————————————————————————— ; DartInputSelect - Select the sound input source on Dartanian ; ; If we are selecting "none" for the input source, then turn off the volume ; and AGC to prevent any noise leakage. Save the old volume and restore it ; later when a new source is selected. If a source has been selected, then ; disable auto sleep otherwise enable auto sleep ; ; On Dart however, there is an additional sound mux in front of DFAC. For sound ; input selection, we will use this hardware instead of that in DFAC. All sound input ; will feed through DFAC's mike input port. ; ; On Dart ,as on TIM, sound input does not work unless AGC is enabled. We ; kludge something to always set AGC. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim) ; Output: d0.b last source ; DartInputSelect @workingreg reg d1/a0 move.w sr,-(sp) ; save the old sr movem.l @workingreg,-(sp) ; save working register ; get pointer to sound control register movea.l UnivInfoPtr,a0 ; point to the ProductInfo table, adda.l DecoderInfoPtr(a0),a0 ; then to the DecoderInfo table, movea.l JAWSAddr(a0),a0 ; then to the Niagra base address, adda.l #(NiagraGUR+PontiSndCtl),a0 ; point sound control register bclr.b #PontiSndMux0,(a0) ; default to auto mike selection ori.w #HiIntMask,sr ; disable ints ; determine is we should use the modem override cmp.b #sndSelectAux,d0 ; is the new input the modem channel bne.s @modemOFF @modemON ; don't preset, might cause "pop" bset.b #PontiSndMux1,(a0) ; set modem sound override bra.s @exitsndmux @modemOFF bclr.b #PontiSndMux1,(a0) ; clr modem sound override @exitsndmux move.l d0,d1 ; save the source information bsr.s HandleAutoSleep ; handle autosleep semaphore ; disable Playthru if using internal mike tst.b d0 ; test the new input source cmp.b #sndSelectMike,d0 ; if it the mic ? blt.s @setsource ; (case 0) no sources bgt.s @modemsource ; (case 2) modem sound source ; btst.b #PontiSndIntMic,(a0) ; check for internal microphone operation beq.s @modemsource ; if external microphone, allow playthru ; move.b #0,d0 ; set playthru to off bsr.s PlayThruVol ; @modemsource moveq #sndSelectMike,d0 ; on dart all inputs through mike port on DFAC @setsource bsr.s AGCInputSelect ; change the source move.l d1,d0 ; restore the source information movem.l (sp)+,@workingreg ; restore register move.w (sp)+,sr ; enable ints rts ENDIF ; {hasNiagra} IF hasJaws | hasNiagra THEN ;—————————————————————————————————————————————————————————————————————————————— ; ; Routine: JawsInitSoundHW,NiagraInitSoundHW ; ; Inputs: D0 - sound volume (0-7) ; A0 - pointer to machine's DecoderInfo table ; A1 - pointer to machine's ProductInfo table ; A6 - return address ; ; Outputs: none ; ; Trashes: D0,D1,A3 ; ; Function: Called by BSR6 from StartInit to set the default volume for Jaws ; and Niagra based machines. Their Batman implementation is different ; from "standard" Batman since they do volume control using the scale ; registers. ;—————————————————————————————————————————————————————————————————————————————— JawsInitSoundHW NiagraInitSoundHW MOVEQ #18,D1 ; map volume to scale value MULU D0,D1 MOVEA.L ASCAddr(A0),A3 ; point to the base of the ASC ASL.B #5,D0 ; shift the sound volume into the upper 3 bits MOVE.B D0,ascVolControl(A3) ; and set the volume MOVE.B D1,bmLeftScaleA(A3) ; channel A plays out left speaker at this volume MOVE.B #0,bmRightScaleA(A3) ; channel A does not play out of the right speaker at all MOVE.B #0,bmLeftScaleB(A3) ; channel B does not play out of the left speaker at all MOVE.B D1,bmRightScaleB(A3) ; channel B plays out right speaker at this volume BRA FinishBatmanInit ; finish up with normal initialization ENDIF IF hasPwrControls THEN ;••••••••••••••••••••••••••••••••••••• Power Manager •••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; HandleAutoSleep - handle the auto sleep semaphore ; ; this code handles the autosleep semaphore. when an input source is selected, ; we increment the semaphore to disable auto sleep. care must be taken to not ; increment the semaphone when changing between microphone and aux, this does ; not change the semaphore state. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim) ; ; a0 pointer to primitives table and globals ; ; Output: d0.b last source ; HandleAutoSleep @workingreg reg d2/a0-a1 movem.l @workingreg,-(sp) ; save working registers move.l PmgrBase,a1 ; point a1 to globals movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table moveq.l #3,d2 ; get selection bits and.b DFAClast(a0),d2 ; beq.s @currentlyOff ; is a source active ?? @currentlySelected ; sound source currently selected tst.b d0 ; check new state, bne.s @exit ; if just new source, set the source subq.b #1,AutoSlpDisable(a1) ; ... if turning off source, dec the nosleep semaphore bra.s @exit @currentlyOff ; sound source currently off tst.b d0 ; check new state, beq.s @exit ; if new source still off, set the source addq.b #1,AutoSlpDisable(a1) ; ... if turning on source, inc the nosleep semaphore @exit movem.l (sp)+,@workingreg ; restore working registers rts ENDIF ; {hasPwrControls} IF hasMSC THEN ;•••••••••••••••••••••••••••••••••••••••••• MSC ••••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; DBLiteDFACInit - send a byte to DFAC using the PMGR micro ; ; Use this routine during initialization before traps are enabled. ; ; Input: D0.B = byte to have the PMGR stuff into DFAC ; A0.L = ptr to DecoderInfo record ; A6.L = return address ; Output: none ; Destroys: D3-D4/D6/A2-A4/A5 ; Called by: BSR6 ; IMPORT USTPMGRSendByte DBLiteDFACInit MOVEQ #sndDBLiteDFAC-256,D0 ; MOVEA.L DecoderInfo.VIA1Addr(A0),A2 ; point to the base of VIA 1 MOVEA.L DecoderInfo.VIA2Addr(A0),A3 ; point to the base of VIA 2 MOVEQ #SetDFAC-256,D3 ; send the command

BIGBSR5 USTPMGRSendByte,A4 MOVE.B D0,D3 ; send the DFAC initialization value BIGBSR5 USTPMGRSendByte,A4 MOVEQ #sndInputOff,D3 ; send the input source (none) BIGBSR5 USTPMGRSendByte,A4 ; RTS6 ;—————————————————————————————————————————————————————————————————————————————— ; DBLiteDFACSend - send a byte to DFAC using the PMGR micro ; ; Use this routine during runtime after traps are enabled. ; ; Input: d0.b = byte to send DFAC (in DFAC order) ; Output: none ; DBLiteDFACSend @saveRegs REG D1/A0 MOVEM.L @saveRegs,-(SP) MOVEA.L ([Expandmem],emSndPrimitives),A0; get the pointer to the vector table MOVE.B D0,DFAClast(A0) ; and update the DFAC register image MOVEQ #3,D1 ; mask off the input source AND.B D0,D1 ; CMPI.B #sndSelectAux,d1 ; is the aux modem sound selected? BNE.S @nonAux ; no, use standard DFAC byte from table MOVE.B @dfacTable(d1),d1 ; yes, get modem dfac byte MOVEA.L ASCBase,a0 ; get base address of asc/batman MOVE.B ascVolControl(a0),d0 ; get current ASC volume, ANDI.B #$E0,d0 ; use as DFAC attenuation OR.B d1,d0 ; bits for modem volume MOVEQ #sndSelectAux,d1 ; BRA.S @dfac ; and set DFAC @nonAux MOVE.B @dfacTable(D1),D0 ; get the appropriate DFAC command byte @dfac LSL.W #8,D0 ; move the DFAC command OR.B D1,D0 ; include the desired input selection MOVE.W D0,-(SP) ; put the bytes to send in a buffer on the stack MOVE.L SP,-(SP) ; pmRBuffer points to it to be safe MOVE.L (SP),-(SP) ; pmSBuffer points to it MOVE.W #2,-(SP) ; pmLength MOVE.W #SetDFAC,-(SP) ; pmCommand MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; have the PMGR stuff the byte in DFAC LEA pmData+2(SP),SP ; toss the parameter block and buffer MOVEM.L (SP)+,@saveRegs RTS @dfacTable DC.B (7<<5)|sndByPassOff|sndTCAOff|sndSelectAux ; 0 = no input source (i.e., play) DC.B (0<<5)|sndByPassOff|sndAGCOn|sndSelectMike ; 1 = microphone DC.B (0<<5)|sndByPassOff|sndAGCOn|sndSelectMike ; 2 = modem sound DC.B (7<<5)|sndByPassOff|sndAGCOn|sndSelectMike ; 3 = undefined (set for modem sound) ;——————————————————————————————————————————————————————————————————————————————

; DBInputSelect - Select the sound input source on DB-Lite ; ; If we are selecting "none" for the input source, then turn off the volume ; and AGC to prevent any noise leakage. Save the old volume and restore it ; later when a new source is selected. If a source has been selected, then ; disable auto sleep otherwise enable auto sleep ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on DB-Lite) ; Output: d0.b last source ; DBInputSelect MOVE.W SR,-(SP) ; save the old sr ori.w #HiIntMask,sr ; disable ints BSR.S HandleAutoSleep ; turn auto-sleep on/off if necessary CMPI.B #sndAuxiliary,D0 ; is it modem sound (aux)? BNE.S @std ; no, continue move.l a0,-(sp) ; save a0 move.l VIA2,a0 ; point to the MSC's sound control register lea MSCSndCntl(a0),a0 ; bset #MSCSndPower,(a0) ; turn on sound power move.l (sp)+,a0 ; restore a0 @std bsr.s InputSelect ; select it as the source MOVE.W (SP)+,SR ; enable ints RTS ; ;—————————————————————————————————————————————————————————————————————————————— ; DBLiteSetVol - Set the playback volume on DBLite's ASC/Batman hardware ; If the modem is selected as the sound source, then set DFAC ; as well. ; ; Input: d0.b = volume level (0-7) ; Output: none ;—————————————————————————————————————————————————————————————————————————————— DBLiteSetVol ; move.l a0,-(sp) move.w sr,-(sp) ; save sr ori.w #HiIntMask,sr ; disable ints movea.l ASCBase,a0 ; get base address of asc/batman lsl.b #5,d0 ; shift volume up to pwm position move.b d0,ascVolControl(a0) ; save it in ASC volume register move.l PMgrBase,a0 ; Modem sound volume is controlled through DFAC tst.b SysTaskFlag(a0) ; are the sound input primitives set up? beq.s @exit ; -> no, don't worry about modem yet movea.l ([Expandmem],emSndPrimitives),a0 ; a0 = ptr to vector table moveq.l #3,d0 ; get selection bits and.b DFAClast(a0),d0 ; cmpi.b #sndSelectAux,d0 ; is the aux modem sound selected? bne.s @exit ; no, set the ASC volume jsrTBL sndDFACSend ; call DFACSend to adjust modem sound @exit move.w (sp)+,sr ; restore ints movea.l (sp)+,a0 rts ENDIF ; {hasMSC} ;•••••••••••••••••••••••••••••••••••• VIA2 DFAC stuff ••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; VIA2DFACInit - send a byte to DFAC using via2 ; ; Use this routine during initialization before traps are enabled. ; ; Input: a0.l = ptr to DecoderInfo record ; a6.l = return address ; Output: none ; Destroys: d0-d1/a3 ; Called by: bsr6 ; IF hasNiagra THEN DartDFACInit movea.l JAWSAddr(a0),a3 ; point to the Niagra base address, adda.l #(NiagraGUR+PontiSndCtl),a3 ; then to the sound control register bclr.b #PontiSndMux0,(a3) ; default to auto mike selection bclr.b #PontiSndMux1,(a3) ; disable modem override **** bra.s TimDFACInit ; fall through to TimDFACInit ENDIF IF hasJaws | hasNiagra THEN TimDFACInit moveq #sndTimDFAC,d0 ; DFAC data to send for Tim bra.s VIA2DFACInit ENDIF IF hasOrwell THEN SpikeDFACInit moveq #sndSpikeDFAC,d0 ; DFAC data to send for Spike **** bra.s VIA2DFACInit ; fall through to VIA2DFACInit ENDIF IF hasOrwell | hasJaws | hasNiagra THEN VIA2DFACInit movea.l VIA2Addr(a0),a3 ; a3 = base addr of via2 bset.b #0,vBufB(a3) ; disable data (to aviod nasty accidental data clocking) bset.b #4,vBufB(a3) ; set clock to high bclr.b #0,vBufB(a3) ; enable data moveq.l #8-1,d1 ; adjust for dbra @Loop asr.b #1,d0 ; shift data byte through carry bcc.s @zeroBit bset.b #3,vBufB(a3) ; write a one bra.s @clock @zeroBit bclr.b #3,vBufB(a3) ; write a zero @clock bclr.b #4,vBufB(a3) ; toggle clock bset.b #4,vBufB(a3) ; toggle clock dbra d1,@Loop ; do all 8 data bytes bset.b #0,vBufB(a3) ; disable data rts6 ;—————————————————————————————————————————————————————————————————————————————— ; VIA2DFACSend - send a byte to DFAC using via2 ; ; Use this routine during runtime after traps are enabled. There are three ; bits in VIA2 used to communicate to DFAC: ; bit 0 = latch enable ; 3 = data ; 4 = data clock ; ; To send data, enable data latch and clock each bit out separately. ; ; Input: d0.b = byte to send DFAC (in DFAC order) ; Output: none ; VIA2DFACSend @saveregs reg d1-d2/a0 movem.l @saveregs,-(sp) move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints ; Update the RAM image of the DFAC register movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table move.b d0,DFAClast(a0) ; update DFAC register image ; Clock the data byte out through VIA2. Data is shifted out ; in DFAC order (LSB first). movea.l VIA2,a0 ; get via2 base addr bset.b #0,vBufB(a0) ; disable data (to aviod nasty accidental data clocking) bset.b #4,vBufB(a0) ; set clock to high bclr.b #0,vBufB(a0) ; drop bit to enable data moveq.l #8-1,d1 ; adjust for dbra @Loop asr.b #1,d0 ; shift data byte through carry bcc.s @zeroBit bset.b #3,vBufB(a0) ; write a one bra.s @clock @zeroBit bclr.b #3,vBufB(a0) ; write a zero @clock bclr.b #4,vBufB(a0) ; toggle clock bset.b #4,vBufB(a0) ; toggle clock dbra d1,@Loop ; do all 8 data bytes bset.b #0,vBufB(a0) ; disable data move.w (sp)+,sr ; enable ints movem.l (sp)+,@saveregs rts ENDIF ; {hasOrwell | hasJaws | hasNiagra} IF hasSonora THEN ;•••••••••••••••••••••••••••••••••••••••• Sonora •••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; SonoraInputSelect - Select the sound input source on Sonora-based Macs ; ; If we are turning off the source (equivalent to disabling recording), then ; re-establish the playback mode. ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) ; Output: none ; SonoraInputSelect cmpi.b #sndMicrophone,d0 ; are we selecting the mike? beq InputSelect ; yes - continue ; Since we're not selecting mike, then enable playback @saveregs reg d1/a0 movem.l @saveregs,-(sp) moveq #sndSonoraDFAC-256,d0 ; DFAC playback mode for Sonora sound jsrTBL sndDFACSend ; call DFACSend routine thru expandmem movem.l (sp)+,@saveregs rts ;—————————————————————————————————————————————————————————————————————————————— ; VailInputSelect - Select the sound input source on Vail ; ; If we are turning off the source (equivalent to disabling recording), then ; re-establish the playback mode. ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) ; Output: none ; VailInputSelect cmpi.b #sndMicrophone,d0 ; are we selecting the mike? beq VailNewInputSelect ; yes - continue @saveregs reg d1/a0 movem.l @saveregs,-(sp) moveq #sndSonoraDFAC-256,d0 ; DFAC playback mode for Sonora sound andi.b #sndPlayThruMask,d0 ; mask off playthru volume move.b SDVolume,d1 ; get the volume lsl.b #5,d1 ; shift it into top 3 bits or.b d1,d0 ; or in last volume jsrTBL sndDFACSend ; call DFACSend routine thru expandmem movem.l (sp)+,@saveregs rts ;—————————————————————————————————————————————————————————————————————————————— ; VailNewInputSelect - Select the sound input source on a Vail ; ; If we are selecting "none" for the input source, then turn off the volume ; and AGC to prevent any noise leakage. Save the old volume and restore it ; later when a new source is selected. Turn on Playthru while recording so that ; we can play and record simultaneously. Turning Playthru on while in record mode ; causes the filtering mechanism to be by-passed in the playback sound path. ; This difference is not audibly noticable in 22kHz mode. ; ; Input: do.b input selection ; 0 = none (off) ; 1 = microphone ; 2 = auxillary (modem sound on Tim, CD on Spike and Eclipse) ; Output: d0.b last source ; VailNewInputSelect @saveregs reg d1/a0-a1 movem.l @saveregs,-(sp) movea.l ([Expandmem],emSndPrimitives),a0; a0 = ptr to vector table move.w sr,-(sp) ; ori.w #HiIntMask,sr ; disable ints moveq.l #3,d2 ; get selection bits to return and.b DFAClast(a0),d2 ; save for return moveq #(sndSelectMask\ ; AND sndPlayThruMask\ AND sndAGCMask),d1 ; mask off selection, volume, and AGC bits and.b DFAClast(a0),d1 ; in the DFAC register image or.b d0,d1 ; and OR them into DFAC image ; Check for volume and AGC to update in DFAC now that a sound source has been selected. ; If we are disabling input, then zero the volume and disable AGC to prevent noise ; leakage, otherwise set the currently selected volume and AGC levels. tst.b d0 ; are we turning off input? beq.s @send ; yes - set no input and zero volume or.b UserVolume(a0),d1 ; set volume level cmpi.b #sndMicrophone,d0 ; are we selecting the mike input? bne.s @send ; no - do not enable AGC or.b UserAGC(a0),d1 ; set AGC level @send move.b d1,d0 ; d0 = new DFAC value bset #sndPlayThruBit,d0 ; set bit jsrTBL sndDFACSend ; call DFACSend routine thru expandmem move.w (sp)+,sr ; enable ints move.b d2,d0 ; return source bits we replaced movem.l (sp)+,@saveregs rts ;—————————————————————————————————————————————————————————————————————————————— ; VailSetVol - Set the playback volume on Sonora hardware ; ; Set the playback volume using the DFAC chip instead of the volume control register ; on Batman. ; ; Input: d0.b = volume level (0-7) ; Output: none ; VailSetVol @SaveRegs reg a0-a1 movem.l @SaveRegs,-(sp) movea.l ASCBase,a0 ; get base address of asc/batman move.l ExpandMem,d1 ; do we have expandmem set up yet?? ble.s @oldWay ; nope, do it the old way movea.l d1,a1 ; move.l emSndPrimitives(a1),d1 ; do we have sound primitives yet?? beq.s @oldWay ; nope, do it the old way movea.l d1,a1 ; point to the table tst.b DFAClast(a1) ; has DFAClast been initialized? bne.s @skipDFAClastInit ; yep, don't reinitialize it... move.b #sndSonoraDFAC,DFAClast(a1) ; initialize DFAClast @skipDFAClastInit moveq #3,d1 ; mask off the input source and.b DFACLast(a1),d1 ; cmpi.b #sndSelectMike,d1 ; is it in record mode?? beq.s @restore ; yes, don't do anything move.b #(7<<5),ascVolControl(a0) ; set volume to seven move.b UserVolume(a1),-(sp) ; save off UserVolume jsrTBL sndPlayThruVol ; head off to set PlayThru volume move.b (sp)+,UserVolume(a1) ; restore original UserVolume @restore movem.l (sp)+,@SaveRegs ; restore registers rts ; and return @oldWay lsl.b #5,d0 ; shift volume up to pwm position move.b d0,ascVolControl(a0) ; save it in ASC volume register movem.l (sp)+,@SaveRegs ; restore registers rts ; and split ENDIF ; {hasSonora} IF hasDJMEMC THEN ;•••••••••••••••••••••••••••••••••••••••• DJMEMC •••••••••••••••••••••••••••••••••••••••• ;—————————————————————————————————————————————————————————————————————————————— ; ; Routine: DJMEMCInitSoundHW ; ; Inputs: D0 - sound volume (0-7) ; A0 - pointer to machine's DecoderInfo table ; A1 - pointer to machine's ProductInfo table ; A6 - return address ; ; Outputs: none ; ; Trashes: D0,A3 ; ; Function: Called by BSR6 from StartInit to set the default volume for DJMEMC ; based machines. Although they have a standard Batman implementation, ; the need to whack on their built-in video to prevent calamity. ;—————————————————————————————————————————————————————————————————————————————— DJMEMCInitSoundHW MOVEA.L ASCAddr(A0),A3 ; point to the base of the ASC ASL.B #5,D0 ; shift the sound volume into the upper 3 bits MOVE.B D0,ascVolControl(A3) ; and set the volume MOVE.W #$7F00,bmLeftScaleA(A3) ; pan channel A full left MOVE.W #$007F,bmLeftScaleB(A3) ; pan channel B full right MOVEQ #1,D0 MOVE.L D0,$F9800100 ; shut off sync to built-in video BEFORE beeping CMPI.L #WmStConst,WarmStart ; If we’re just powering on, BNE FinishBatmanInit ; then just go on MOVE.B #0,$50F14f2f ; otherwise, reset the Sound Block Configuration register BRA FinishBatmanInit ; finish up with normal initialization ENDIF ;•••••••••••••••••••••••••••••••••••••••• Cyclone ••••••••••••••••••••••••••••••••••••••• CycloneSndStubNoRam Rts6 CycloneSndStub2 Moveq #0,D0 CycloneSndStub1 Rts ;••••••••••••••••••••••••••••••••••••••••••• PDM •••••••••••••••••••••••••••••••••••••••••• PDMSndStubNoRam Rts6 PDMSndStub2 Moveq #0,D0 PDMSndStub1 Rts IF hasPratt THEN ;•••••••••••••••••••••••••••••••••••••••• Blackbird ••••••••••••••••••••••••••••••••••••••• ;————————————————————————————————————————————————————————————————————————————————————————— ; DoNothing routines - The following routines simply return to the caller (used for ; unimplemented sound primitives). DoNothingViaA6 RTS6 DoNothing rts ;—————————————————————————————————————————————————————————————————————————————— ; ; Routine: WhitneyInitSoundHW ; ; Inputs: D0 - sound volume (0-7) ; D1 - 0 is called via the RAMless routine, else 1 ; A0 - pointer to machine's DecoderInfo table ; A1 - pointer to machine's ProductInfo table ; A6 - return address ; ; Outputs: none ; ; Trashes: D0,A3 ; ; Function: Called by InitSoundHW (via BSR6) to configure hardware for Whitney ; based machines (i.e. Blackbird). Called before the trap dispatcher ; is initialized. Always returns via (A6). ;—————————————————————————————————————————————————————————————————————————————— BB_BASE EQU $10000 ; sound buffer base addr for bootbeep (64K) WhitneyInitSoundHW movea.l ASCAddr(a0),a3 ; point to the base of the ASC ; Set Whitney sound FIFO base address ; NOTE: We use the value of d1 to determine how to set the base address. If d1 ; is 0, then we know that we entered via the RAMless entry point (called immediately ; before and after bootbeep). In this case, we know we have some RAM available, ; so we temporarily grab some low in memory for the sound buffer. ; If d1 is 1, we set the "real" FIFO base address to just above the boot/start globals, ; since this is where space is allocated for it by the SizeSoundBuffer routine. tst.w d1 bne.s @setRealFIFOBase @setTempFIFOBase move.l #BB_BASE,wSndFIFOBase(a3) ; set FIFO base for BootBeep bra.s @setSndCntl @setRealFIFOBase movem.l a0,-(sp) ; (don't worry, the stack exists for this path) movea.l BootGlobPtr,a0 adda.l StartGlobals.sgTopOff(a0),a0 move.l a0,wSndFIFOBase(a3) ; the REAL sound FIFO base movem.l (sp)+,a0 @setSndCntl ; Set up the Singer control registers move.w #((%0100<