mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-22 23:29:27 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1955 lines
69 KiB
Plaintext
1955 lines
69 KiB
Plaintext
;__________________________________________________________________________________________________
|
|
;
|
|
; File: ImmgPrimitives.a
|
|
;
|
|
; Contains: Primitive tables and init routines for the internal modem manager
|
|
;
|
|
; Written by: Steven Swenson
|
|
;
|
|
; Copyright © 1994-1994 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM3> 1/26/94 rab Removed padForOverpatch stuff from the end of this file
|
|
; (SuperMario does not use itÉ).
|
|
; <SM2> 12/21/93 ged Changed rate11_025khz label to newer rate11025hz definition.
|
|
; <H13> 6/1/93 SES Made modifications as per SPI review on 6/1/93. The only real
|
|
; change was to vector the command count and receive count table
|
|
; pointers through global storage rather than lea's inside the
|
|
; mdmPrime routine (prevents someone who wants to patch the count
|
|
; tables from having to patch the entire mdmPrime routine). The
|
|
; other changes were to add comments, and rearrange a few of the
|
|
; EQU's into a more logical grouping.
|
|
; <H12> 5/23/93 SES Made changes from code review on 5/19/93.
|
|
; <H11> 5/21/93 SES Made the Slot9Handler routine check the status register
|
|
; interrupt level mask. If the mask is greater than 2, the
|
|
; routine sets the mask down to 2 and then restores it to whatever
|
|
; it was. This is to fix a problem that occurs because the Elan
|
|
; ethernet driver interrupt handling routine sometimes leaves the
|
|
; interrupt mask in the status register at 4 or 6, which causes
|
|
; problems on Optimus (when the slot 9 interrupt is really handled
|
|
; by the level 3 interrupt handler - if the level 3 handler cannot
|
|
; execute, the slot 9 interrupt is not cleared, and an infinite
|
|
; loop results).
|
|
; <H10> 5/17/93 SES Changed modem sound control and set up primitives. Sound control
|
|
; keeps track of when it has been called on and off so that it
|
|
; does not do on or off more than once in a row. The set up
|
|
; routine initializes the saved input source to none and the saved
|
|
; playthru volume to zero.
|
|
; <H9> 5/11/93 SES Screwed up! One minor mod needed to happen to make the previous
|
|
; fix work, the moveq instruction does not work with that large an
|
|
; operand!
|
|
; <H8> 5/11/93 SES Made mdmWakeup3615 primitive for Optimus return
|
|
; immgInvalidSelector error rather than no error, since the
|
|
; routine does not do anything (and in the future, some other
|
|
; routine might actually do something).
|
|
; <H7> 5/10/93 SES In order to alleviate a possible bus float situation, wrote data
|
|
; to the modem ID register instead of the ROMBase, since the IO
|
|
; data bus needed to be cleared, not the processor data bus.
|
|
; <H6> 5/6/93 SES Altered sound control so that the play through volume is set to
|
|
; equal the slider volume during modem sound transactions.
|
|
; <H5> 5/4/93 SES Removed machine primitives and replaced them with the dispatch
|
|
; functions in the IntModemMgr.a file.
|
|
; <H4> 4/27/93 SES Enhanced modem manager and adding primitives as per code review
|
|
; on 4/22/93. Moved dispatcher to IntModemMgr.a. Split
|
|
; primitives into machine primitives and modem primitives.
|
|
; Significantly reduced size of the command and reply lookup
|
|
; tables.
|
|
; <H3> 4/24/93 SES Played around with how sound is handled on Optimus for the
|
|
; modem.
|
|
; <H2> 4/15/93 SES Changed Optimus primitives so that machine does not hang when
|
|
; powered off. This means that the power control primitive
|
|
; disables interrupts from the modem when the modem is "turned
|
|
; off." Also implemented the sound control primitive for Optimus
|
|
; (hits sound control bit in sound control register. Finally,
|
|
; altered the structure of the primitives table to have an offset
|
|
; to the next modem table, effectively creating a linked list of
|
|
; modem tables so that they do not have to be physically
|
|
; contiguous in memory.
|
|
; <1> 4/8/93 SES first checked in
|
|
; <H1> 4/8/93 SES First checked in
|
|
;__________________________________________________________________________________________________
|
|
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'UniversalEqu.a'
|
|
INCLUDE 'ROMEqu.a'
|
|
INCLUDE 'IOPrimitiveEqu.a'
|
|
INCLUDE 'IntModemMgrEqu.a'
|
|
INCLUDE 'IntModemMgrPrivEqu.a'
|
|
INCLUDE 'PowerPrivEqu.a'
|
|
INCLUDE 'Sound.a'
|
|
|
|
MACHINE MC68020 ; <H3>
|
|
|
|
STRING ASIS
|
|
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; BEGIN OPTIMUS MODEM PRIMITIVES
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; Equates for Optimus modem primitives
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
OptMdmBase equ $50F09000
|
|
|
|
; Optimus modem address offsets
|
|
|
|
OptSPIMdmCtl EQU $000
|
|
OptSndCtl EQU $400
|
|
OptSPISftReg EQU $800
|
|
OptLmpSftCtl EQU $C00
|
|
OptMdmIDReg EQU $FFC
|
|
|
|
; Optimus OptSPIMdmCtl bit definitions
|
|
OptSPIMdmId EQU 0 ; (1 = SPI modem connected)
|
|
OptSPIAck EQU 2 ; (1 = ack idle)
|
|
OptSPIReq EQU 3 ; (1 = req idle)
|
|
OptSPIIrq EQU 4 ; (1 = interrupting)
|
|
OptRingDet EQU 5 ; ring detect bit
|
|
|
|
; Optimus OptLmpSftCtl bit definitions
|
|
OptLmpSPIDir EQU 4 ; shift direction control bit
|
|
|
|
; Optimus OptSndCtl bit definitions
|
|
bOptIntMask EQU 0
|
|
bOptSndMask EQU 1
|
|
|
|
; Bit definitions for the power manager status bits for modem
|
|
|
|
bPMMdmPower EQU 0 ; Modem power
|
|
bPMRingWakeUp EQU 2 ; Ring wake up enable
|
|
bPMMdmInstall EQU 3 ; Modem installed
|
|
bPMRingDet EQU 4 ; Ring detect
|
|
|
|
; equ for Optimus slot interrupt hack
|
|
|
|
OptHackSlotNum EQU 9 ; slot number for interrupt handler
|
|
|
|
|
|
; equ's for dummy slot 9 interrupt handler hack fix of Elan ethernet interrupt handler bug
|
|
|
|
statMaskBits EQU $0700 ; mask for status bits in SR
|
|
level3Bits EQU $0300 ; bits for checking level 3 and above mask in SR
|
|
level2Bits EQU $0200 ; bits for setting mask in SR to level 2
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; Equates for Baby Rock modem primitives
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; Private storage data structures for 3615 primitives
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
immg3615Rec RECORD 0
|
|
ModemType DS.L 1 ; ID of installed modem
|
|
ModemBase DS.L 1 ; base address of the modem
|
|
Slot9Addr DS.L 1 ; pointer to slot 9 handler queue element
|
|
SndInputSrc DS.B 1 ; saved sound input source ; <H3>
|
|
PlayThruVol DS.B 1 ; saved sound playthrough volume ; <H3>
|
|
PreviousCmd DS.W 1 ; the last command executed through the call; <H10>
|
|
SendTable DS.L 1 ; pointer to modem prime send table
|
|
RecvTable DS.L 1 ; pointer to modem prime receive table
|
|
size EQU *-immg3615Rec ; size of record
|
|
ENDR
|
|
|
|
|
|
immg3615SlotQEl RECORD 0
|
|
sqLink DS.L 1 ; link address
|
|
sqType DS.W 1 ; type of queue element
|
|
sqPrio DS.W 1 ; priority
|
|
sqAddr DS.L 1 ; address of handler
|
|
sqParm DS.L 1 ; optional A1 pointer
|
|
sqInt9Count DS.L 1 ; number of times in slot 9 interrupt
|
|
sqInt3Count DS.L 1 ; number of times in level 3 interrupt
|
|
size EQU *-immg3615SlotQEl ; size of record
|
|
ENDR
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; Private storage data structures for Baby Rock primitives
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
immgBabyRockRec RECORD 0
|
|
ModemType DS.L 1 ; ID of installed modem
|
|
ModemBase DS.L 1 ; base address of the modem
|
|
SndMonState DS.W 1 ; current modem sound monitoring state
|
|
SndMonVolume DS.W 1 ; current modem sound volume level
|
|
size EQU *-immgBabyRockRec ; size of record
|
|
ENDR
|
|
|
|
|
|
|
|
ImmgPrim PROC
|
|
EXPORT ImmgBabyRock
|
|
ImmgBabyRock
|
|
;----------------------------------------------------------------------------------------
|
|
; ROM root table structure for modem manager initialization for BabyRock Modem in Blackbird.
|
|
; See IntModemMgrPrivEqu.a for the structure that is built below
|
|
;----------------------------------------------------------------------------------------
|
|
immgMdmListHeadBabyRock
|
|
DC.L mdmPrimsBabyRock ; offset to the BabyRock primitives
|
|
DC.L 0 ; no further modems supported
|
|
EndImmgBabyRock
|
|
|
|
mdmPrimsBabyRock
|
|
DC.W 0 ; flags
|
|
DC.W 0 ; number of primitives (filled in at init time)
|
|
DC.L mdmTypeBabyRock-mdmPrimsBabyRock ; offset to modem type routine
|
|
DC.L mdmPowerBabyRock-mdmPrimsBabyRock ; offset to modem power routine
|
|
DC.L mdmWakeupBabyRock-mdmPrimsBabyRock ; offset to modem wakeup on ring control routine
|
|
DC.L mdmStatusBabyRock-mdmPrimsBabyRock ; offset to modem status routine
|
|
DC.L mdmPrimeBabyRock-mdmPrimsBabyRock ; offset to modem prime routine
|
|
DC.L mdmSndCtlBabyRock-mdmPrimsBabyRock ; offset to modem sound control routine
|
|
DC.L mdmExistsBabyRock-mdmPrimsBabyRock ; offset to modem exists routine
|
|
DC.L mdmSetUpBabyRock-mdmPrimsBabyRock ; offset to modem set up routine
|
|
DC.L mdmTearDownBabyRock-mdmPrimsBabyRock; offset to modem tear down routine
|
|
DC.L mdmNameBabyRock-mdmPrimsBabyRock ; offset to modem name routine
|
|
DC.L mdmSndVolBabyRock-mdmPrimsBabyRock ; offset to modem sound volume routine
|
|
DC.L mdmSndHWBabyRock-mdmPrimsBabyRock ; offset to system sound arbitration routine
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmTypeBabyRock
|
|
;
|
|
; Entry: a1 = modem primitive global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
; a0 = modem type
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Returns the modem type stored in global storage.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmTypeBabyRock
|
|
WITH PowerDispRec,PMgrHookDispRec
|
|
MOVE.L #(PModemType<<16)|\
|
|
(PMgrHookDisp<<0),D0 ; get the modem type
|
|
_PowerDispatch
|
|
MOVEA.L D0,A0 ; return modem type
|
|
MOVEQ #noErr,D0 ; never any errors
|
|
RTS
|
|
ENDWITH
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmPowerBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = no error
|
|
;
|
|
; Trashes: none
|
|
;
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmPowerBabyRock
|
|
WITH immgParamBlock
|
|
MOVE.B #%00001000,D0 ; select power cmd on channel C
|
|
TST.W immgCommand(a0) ; IF Power Off Modem THEN
|
|
BNE.S @CallSerPwr ; .
|
|
ORI.B #(1<<7),D0 ; Set Power Off Bit
|
|
@CallSerPwr _SerialPower ; Call Serial Power
|
|
RTS
|
|
ENDWITH
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmWakeupBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Returns immgInvalidSelector error, while we wait for PG&E to É
|
|
; support wake up on ring. There is no software to take advantage of the wake up on ring
|
|
; feature at the present time. This routine returns an error so that when software
|
|
; becomes available that can take advantage of wake up on ring, it can check the return
|
|
; result from this function to determine if the desired behavior has taken place.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmWakeupBabyRock
|
|
MOVE.W #immgInvalidSelector,D0 ; no good
|
|
RTS
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmStatusBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Constructs status byte from various sources.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmStatusBabyRock
|
|
BRA DoPmgrCmd ; run through the Pmgr
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmPrimeBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
;
|
|
; Sends and receives bytes to/from the modem.
|
|
;
|
|
; Processor interrupts are masked during this command. The SCC data is polled during the
|
|
; call and the data is stored on the stack. Great pains are taken to keep the stack clear
|
|
; for the SCC data. At the end of the call, the PollProc is called to remove the SCC data
|
|
; from the stack.
|
|
;
|
|
; Interrupts can be disabled by this routine for an indeterminate amount of time. In
|
|
; practice, the call takes no more than about 4ms. The time out value for the communication
|
|
; of one byte of data to or from the modem is 32ms. It is therefore theoretically possible
|
|
; that in a worst case scenario, say some hardware problem where the communication to and
|
|
; from the modem takes 31ms, and there are 100 bytes to receive from the modem, that
|
|
; interrupts would be disabled for 3.1sec! This problem is left to future authors of the
|
|
; primitive.
|
|
;
|
|
; SPI stands for Serial Port Interface, and is a standard interface specification for
|
|
; the Motorola 6805 microcontroller.
|
|
;
|
|
; There is no attempt by this primitive to recover from any errors that may be encountered
|
|
; during the sending or receiving of bytes to/from the modem. If an error does occur, it
|
|
; is reported, but the hardware may not be in the expected state.
|
|
;
|
|
; Pointers to the send and receive count tables are stored in the mdmSetUp routine above.
|
|
; This is done so that patching the tables is easy.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmPrimeBabyRock
|
|
DoPmgrCmd
|
|
_PMgrOp
|
|
RTS
|
|
|
|
;------------------------------------------------------------------------------------------------
|
|
; mdmSndCtlBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Control modem sound for the BabyRock modem. The caller can either enable or disable the modem
|
|
; sound channel. Note that this channel is a software channel that sends DMA'ed (is that an
|
|
; adjective?) sound samples from the modem to the sound manager. The relative volume of that
|
|
; channel is controlled via the mdmSndVolBabyRock primitive.
|
|
;------------------------------------------------------------------------------------------------
|
|
|
|
mdmSndCtlBabyRock
|
|
|
|
WITH immgParamBlock,immgBabyRockRec
|
|
|
|
@savedRegs REG d1
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
move.w immgCommand(a0),d1 ; D1 -> sound command to process
|
|
|
|
@chkOnOff cmpi.w #immgSndOff,d1 ; check for sound monitoring on/off
|
|
beq.s @valid
|
|
cmpi.w #immgSndOn,d1
|
|
beq.s @valid
|
|
|
|
@undefined bra.s @done ; sound command unrecognized, leave
|
|
|
|
@valid cmp.w SndMonState(a1),d1 ; is modem sound already in this state?
|
|
beq.s @done ; if so, then we're doneÉ
|
|
|
|
cmpi.w #immgSndOn,d1
|
|
bne.s @turnOff
|
|
|
|
@turnOn ; Add Codec programming, not done by primitive code
|
|
|
|
; Set codec interface to TCM320AC36
|
|
move.b #2,HardRockCodecICR
|
|
|
|
; Set sample rate to SCLK * 256 (i.e. singer clock)
|
|
move.b #1,HardRockCodecSRCR
|
|
|
|
; Enable codec
|
|
move.b #1,HardRockCodecEnReg
|
|
|
|
; Call interface code
|
|
move.l #immgSndOn,-(sp)
|
|
bsr ModemSoundCntl
|
|
addq #4,sp
|
|
bne.s @noGood
|
|
|
|
bra.s @logIt
|
|
|
|
@turnOff move.l #immgSndOff,-(sp)
|
|
bsr ModemSoundCntl
|
|
addq #4,sp
|
|
bne.s @noGood
|
|
|
|
@logIt move.w d1,SndMonState(a1) ; save state for next time
|
|
|
|
@noGood ;not much we can do since the interface does not allow an error return, at least
|
|
;we don't set the SndMonState field incorrectly - so future calls have a shot at
|
|
;working (of course this shouldn't happen, butÉ)
|
|
|
|
@done moveq #noErr,d0
|
|
movem.l (sp)+,@savedRegs ; restore registers
|
|
@exit rts
|
|
|
|
ENDWITH
|
|
|
|
;___________________________________________________________________________________________
|
|
;
|
|
; Modem Hardware Info Structure
|
|
;
|
|
; Used to store pass information about the modem sound hardware until we get the
|
|
; Internal Modem Manager on-line (so that we can handle various modem hardware during
|
|
; development).
|
|
;___________________________________________________________________________________________
|
|
|
|
ModemHWInfo RECORD 0
|
|
Flags DS.B 1 ; bit flags specifying various modem HW modes
|
|
reserved1 DS.B 1 ; reserved for future use
|
|
mSrcSampleRate DS.L 1 ; modem sound source sample rate (unsigned fixed)
|
|
reserved2 DS.L 1 ; reserved for future use
|
|
reserved3 DS.L 1 ; reserved for future use
|
|
reserved4 DS.L 1 ; reserved for future use
|
|
|
|
ModemHWInfoSize EQU * ; size of ModemHWInfo
|
|
ENDR
|
|
|
|
; =====================================================================
|
|
;
|
|
; void ModemSoundCntl(Boolean enable);
|
|
;
|
|
; calls the custom sound primitive to enable/disable modem sound
|
|
;
|
|
; NOTE: The sample rate passed in the ModemHWInfo structure field must
|
|
; be in unsigned fixed format. This format is the same as that
|
|
; described in IM1 except the msb is not interpreted as a
|
|
; sign bit (e.g. AC440000 is 44,100 and NOT -21,436).
|
|
;
|
|
; NOTE2: Make sure the CODEC interface has been set up correctly
|
|
; before calling this routine (we don't touch it).
|
|
;
|
|
; =====================================================================
|
|
HrClockSrcBit EQU 0 ; bit is one if using external clock, zero if using Singer clk
|
|
|
|
ModemSoundCntl
|
|
|
|
ModemSndFrame RECORD {A6Link},DECR
|
|
enable DS.L 1
|
|
return DS.L 1
|
|
A6Link DS.L 1
|
|
reserved DS.L 1
|
|
LocalSize EQU *
|
|
ENDR
|
|
|
|
@savedRegs reg d0-d3/a0-a1
|
|
|
|
WITH ModemHWInfo,ModemSndFrame,ExpandMemRec
|
|
|
|
link a6,#LocalSize ; set up stack frame
|
|
movem.l @savedRegs,-(sp)
|
|
|
|
@gotIt moveq #ModemHWInfoSize,d0 ; allocate *TEMPORARY* pass-in structure
|
|
_NewPtr ,SYS,CLEAR
|
|
bne.s @done
|
|
movea.l a0,a1
|
|
|
|
;********************* SET HARDWARE CALL MONITORING ATTRIBUTES HERE *********************
|
|
;bset #HrClockSrcBit,Flags(a1) ; flag external clock for HardRock CODEC
|
|
bclr #HrClockSrcBit,Flags(a1) ; flag Singer clock for HardRock CODEC
|
|
move.l #rate11025hz,mSrcSampleRate(a1) ; set sample rate in unsigned fixed format
|
|
|
|
moveq #sndModemSndOff,d0 ; assume modem sound off
|
|
tst.l enable(a6) ; see what the caller wants
|
|
beq.s @execute ; we guessed right, so execute primitive
|
|
moveq #sndModemSndOn,d0 ; no, select modem sound on
|
|
|
|
@execute movea.l ([ExpandMem],emSndPrimitives),a0 ; get the address of the sound primitive table
|
|
move.l sndModemSound*4(a0),d1 ; is there a handler?
|
|
beq.s @leave ; no, just exit
|
|
move.l d1,a0
|
|
jsr (a0) ; call the ioprimitive
|
|
bne.s @primFailed
|
|
@primOK clr.w d3 ; save passed value for later check
|
|
bra.s @leave
|
|
@primFailed moveq #-1,d3 ; save error value for later check
|
|
|
|
@leave movea.l a1,a0
|
|
_DisposPtr ; get rid of *TEMPORARY* pass-in structure
|
|
|
|
@done movem.l (sp)+,@savedRegs
|
|
unlk a6
|
|
rts
|
|
|
|
ENDWITH
|
|
|
|
|
|
; ===================================================================== ;
|
|
;
|
|
; Boolean Error ModemHWCntl(Boolean enable);
|
|
;
|
|
; calls the custom sound primitive to Grab/Release modem sound hardware
|
|
;
|
|
; ===================================================================== ;
|
|
ModemHWCntl
|
|
|
|
ModemHWCFrame RECORD {A6Link},DECR
|
|
enable DS.L 1
|
|
return DS.L 1
|
|
A6Link DS.L 1
|
|
reserved DS.L 1
|
|
LocalSize EQU *
|
|
ENDR
|
|
|
|
@savedRegs reg d0-d2/a0-a1
|
|
|
|
WITH ModemHWCFrame,ExpandMemRec
|
|
|
|
link a6,#LocalSize ; set up stack frame
|
|
movem.l @savedRegs,-(sp)
|
|
|
|
moveq #sndReleaseHW,d0 ; assume modem sound release
|
|
tst.l enable(a6) ; see what the caller wants
|
|
beq.s @execute ; we guessed right, so execute primitive
|
|
moveq #sndGrabHW,d0 ; no, select modem sound grab
|
|
|
|
@execute movea.l ([ExpandMem],emSndPrimitives),a0 ; get the address of the sound primitive table
|
|
move.l sndSoundHWCntl*4(a0),d1 ; is there a handler?
|
|
beq.s @done ; no, just exit
|
|
move.l d1,a0
|
|
jsr (a0) ; call the ioprimitive
|
|
bne.s @problem
|
|
|
|
moveq #0,d0 ; flag that call was successful
|
|
bra.s @done
|
|
|
|
@problem moveq #1,d0 ; flag that call did not succeed
|
|
@done movem.l (sp)+,@savedRegs
|
|
unlk a6
|
|
rts
|
|
|
|
ENDWITH
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmExistsBabyRock
|
|
;
|
|
; Entry: none
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Check if a BabyRock modem is installed in the box.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmExistsBabyRock
|
|
WITH PowerDispRec,PMgrHookDispRec
|
|
MOVE.L #(PModemType<<16)|\
|
|
(PMgrHookDisp<<0),D0 ; get the modem type
|
|
_PowerDispatch
|
|
TST.W D0 ;
|
|
BEQ.S @noModem
|
|
MOVEQ #noErr,D0 ; indicate modem exists
|
|
RTS
|
|
@noModem
|
|
MOVE.W #immgNoBoardErr,d0 ; indicate no board
|
|
RTS
|
|
ENDWITH
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSetUpBabyRock
|
|
;
|
|
; Entry: none
|
|
;
|
|
; Exit: d0 = result code
|
|
; a0 = pointer to modem primitives globals
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Set up the primitives for the 3615 modem.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSetUpBabyRock
|
|
@savedRegs REG a1-a3
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
WITH immgBabyRockRec
|
|
|
|
; allocate private storage for modem primitives
|
|
|
|
move.l #immgBabyRockRec.size,d0 ; get size of private storage
|
|
_NewPtr ,SYS,CLEAR ; get a pointer in the system heap ; <H10>
|
|
tst.w d0 ; check for errors
|
|
bne.w @error1 ; if no memory, cannot continue
|
|
movea.l a0,a3 ; a3 = pointer to private storage
|
|
|
|
movea.l #HardRockSlotBase,a2 ; get base address of modem
|
|
move.l a2,ModemBase(a3) ; store base address
|
|
|
|
movea.l #FIFOMEM_BASE,a0 ; set up the HardRock FIFO bases (for DMA)
|
|
IMPORT GetRealProc
|
|
bsr.l GetRealProc
|
|
movea.l a0,a1
|
|
adda.l #FIFO_0_OFFSET,a1
|
|
move.l a1,HardRockFifoBase0
|
|
movea.l a0,a1
|
|
adda.l #FIFO_1_OFFSET,a1
|
|
move.l a1,HardRockFifoBase1
|
|
movea.l a0,a1
|
|
adda.l #FIFO_2_OFFSET,a1
|
|
move.l a1,HardRockFifoBase2
|
|
|
|
WITH PowerDispRec,PMgrHookDispRec
|
|
MOVE.L #(PModemType<<16)|\
|
|
(PMgrHookDisp<<0),D0 ; get the modem type
|
|
_PowerDispatch
|
|
ENDWITH
|
|
move.l d0,ModemType(a3) ; store the modem type in private storage
|
|
|
|
move.w #immgSndOff,SndMonState(a3) ; initialize state variables to track modem sound
|
|
move.w #$FF,SndMonVolume(a3) ; initialize modem sound volume (to full)
|
|
|
|
movea.l a3,a0 ; return pointer to primitives globals
|
|
moveq #noErr,d0 ; no error
|
|
|
|
@exit movem.l (sp)+,@savedRegs ; restore registers
|
|
rts
|
|
|
|
; indicate initialization error
|
|
@error1 move.w #immgInitError,d0 ; bad...
|
|
bra.s @exit
|
|
|
|
ENDWITH
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmTearDownBabyRock
|
|
;
|
|
; Entry: a1 = pointer to modem primitives globals
|
|
;
|
|
; Exit: d0 = no error
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Deallocates everything that the set up routine allocated and sets PrimeTime so that
|
|
; no modem interrupts are generated.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmTearDownBabyRock
|
|
WITH immgBabyRockRec
|
|
|
|
; deallocate private storage for modem primitives
|
|
|
|
movea.l a1,a0 ; A0 -> pointer to private storage
|
|
_DisposPtr
|
|
|
|
moveq #noErr,d0 ; no error
|
|
|
|
@exit rts
|
|
|
|
ENDWITH
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmNameBabyRock
|
|
;
|
|
; Entry: a0 = pointer to string buffer
|
|
; a1 = pointer to modem primitives globals
|
|
;
|
|
; Exit: d0 = no error
|
|
; a0 = pointer to null terminated string
|
|
;
|
|
; Trashes: A1
|
|
;
|
|
; Returns the name of the modem.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmNameBabyRock
|
|
MOVE.L A0,-(sp) ; save pointer
|
|
|
|
MOVEA.l A0,A1 ; destination
|
|
LEA @modemName,A0 ; source (skip over length byte)
|
|
@loop MOVE.B (A0)+,(A1)+ ; copy one byte
|
|
BNE.S @loop ; keep copying until null terminal byte is copied
|
|
|
|
MOVEA.L (SP)+,A0 ; return modem name in A0
|
|
MOVEQ #noErr,D0 ; no error
|
|
|
|
@exit RTS
|
|
|
|
@modemName DC.B 'Baby Rock'
|
|
DC.B 0
|
|
|
|
ALIGN 2
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSndVolBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Controls the volume of the modem sound channel relative to the overall hardware sound
|
|
; level.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSndVolBabyRock
|
|
WITH immgParamBlock,immgBabyRockRec,ExpandMemRec
|
|
|
|
@savedRegs REG a0/d1
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
move.w immgCommand(a0),d1 ; D1 -> sound command to process
|
|
|
|
@chkCmd cmpi.w #immgVolSet,d1 ; dispatch to appropriate codeÉ
|
|
beq.s @setVol
|
|
cmpi.w #immgVolRead,d1
|
|
beq.s @readVol
|
|
|
|
@undefined bra.s @badCmd ; sound command unrecognized, leave
|
|
|
|
@setVol cmpi.w #2,immgLength(a0) ; verify the volume parameter format
|
|
bne.s @formatErr
|
|
move.w ([immgSBuffer,a0]),d0 ; get volume level to set
|
|
|
|
movea.l ([ExpandMem],emSndPrimitives),a0 ; get the address of the sound primitive table
|
|
move.l sndModemSndVol*4(a0),d1 ; is there a handler?
|
|
beq.s @problemo ; no, so bail
|
|
move.l d1,a0
|
|
jsr (a0) ; call the snd primitive
|
|
bne.s @problemo ; bail if the primitive returns an error
|
|
|
|
move.w d0,SndMonVolume(a1) ; save current modem sound level (for later read calls)
|
|
bra.s @normal
|
|
|
|
@readVol move.w #2,immgLength(a0) ; set up for volume parameter return
|
|
tst.l immgRBuffer(a0) ; be paranoid and make sure a return buff ptr is present
|
|
beq.s @formatErr
|
|
move.w SndMonVolume(a1),([immgRBuffer,a0])
|
|
bra.s @normal
|
|
|
|
@problemo move.w #immgCommandError,d0 ; signals a generic problem with command execution
|
|
bra.s @exit
|
|
@formatErr move.w #immgSendEndErr,d0 ; simulate a data transfer error
|
|
bra.s @exit
|
|
@badCmd move.w #immgInvalidCommand,d0
|
|
bra.s @exit
|
|
|
|
@normal moveq #noErr,d0
|
|
|
|
@exit movem.l (sp)+,@savedRegs ; restore registers
|
|
rts
|
|
|
|
ENDWITH
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSndHWBabyRock
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Allows the caller to negotiate/release exclusive control of the sound hardware.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSndHWBabyRock
|
|
WITH immgParamBlock,immgBabyRockRec,ExpandMemRec
|
|
|
|
@savedRegs REG a0-a1/d1
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
move.w immgCommand(a0),d1 ; D1 -> sound command to process
|
|
|
|
@chkCmd cmpi.w #immgSndRelease,d1 ; dispatch to appropriate codeÉ
|
|
beq.s @valid
|
|
cmpi.w #immgSndTakeover,d1
|
|
beq.s @valid
|
|
|
|
@undefined bra.s @badCmd ; sound command unrecognized, leave
|
|
|
|
@valid movea.l ([ExpandMem],emSndPrimitives),a1 ; get the address of the sound primitive table
|
|
move.l sndSoundHWState*4(a1),d0 ; is there a handler?
|
|
beq.s @problemo ; no, so bail
|
|
move.l d0,a1
|
|
jsr (a1) ; call the snd primitive
|
|
bne.s @problemo ; bail if the primitive returns an error
|
|
|
|
cmpi.w #immgSndRelease,d1 ; see if command makes sense given current HW state
|
|
bne.s @isGrabOK
|
|
@isRlseOK cmpi.b #sndReleaseHW,d0
|
|
beq.s @problemo ; (bail if command is release and we are already released)
|
|
bra.s @tryRelease
|
|
@isGrabOK cmpi.b #sndReleaseHW,d0
|
|
bne.s @problemo ; (bail if command is grab and HW is already "grabbed")
|
|
|
|
@tryGrab move.w #sndGrabHW,d0
|
|
bra.s @arbitrate
|
|
|
|
@tryRelease move.w #sndReleaseHW,d0
|
|
|
|
@arbitrate movea.l ([ExpandMem],emSndPrimitives),a1 ; get the address of the sound primitive table
|
|
move.l sndSoundHWCntl*4(a1),d1 ; is there a handler?
|
|
beq.s @problemo ; no, so bail
|
|
move.l d1,a1
|
|
jsr (a1) ; call the snd primitive
|
|
bne.s @arbFailed
|
|
|
|
@arbGood move.w #immgArbOK,d1
|
|
bra.s @normal
|
|
|
|
@arbFailed move.w #immgArbFailed,d1
|
|
|
|
@normal moveq #noErr,d0
|
|
bra.s @report
|
|
|
|
@problemo move.w #immgCommandError,d0 ; signals a generic problem with command execution
|
|
move.w #immgArbFailed,d1
|
|
bra.s @report
|
|
@badCmd move.w #immgInvalidCommand,d0
|
|
move.w #immgArbFailed,d1
|
|
|
|
@report move.w #2,immgLength(a0)
|
|
tst.l immgRBuffer(a0) ; be paranoid and check for receive buffer ptr
|
|
beq.s @formatErr
|
|
move.w d1,([immgRBuffer,a0])
|
|
bra.s @exit
|
|
|
|
@formatErr move.w #immgRecvEndErr,d0 ; simulate a data transfer error
|
|
|
|
@exit movem.l (sp)+,@savedRegs ; restore registers
|
|
rts
|
|
|
|
ENDWITH
|
|
|
|
|
|
|
|
EXPORT ImmgOptimus
|
|
ImmgOptimus
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; ROM root table structure for modem manager initialization for Optimus.
|
|
; See IntModemMgrPrivEqu.a for the structure that is built below
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
immgMdmListHeadOpt
|
|
DC.L mdmPrims3615-immgMdmListHeadOpt ; offset to 3615 primitives
|
|
DC.L 0 ; no further modems supported
|
|
|
|
EndImmgOptimus
|
|
|
|
|
|
mdmPrims3615
|
|
DC.W 0 ; flags
|
|
DC.W 0 ; number of primitives (filled in at init time)
|
|
DC.L mdmType3615-mdmPrims3615 ; offset to modem type routine
|
|
DC.L mdmPower3615-mdmPrims3615 ; offset to modem power routine
|
|
DC.L mdmWakeup3615-mdmPrims3615 ; offset to modem wakeup on ring control routine
|
|
DC.L mdmStatus3615-mdmPrims3615 ; offset to modem status routine
|
|
DC.L mdmPrime3615-mdmPrims3615 ; offset to modem prime routine
|
|
DC.L mdmSndCtl3615-mdmPrims3615 ; offset to modem sound control routine
|
|
DC.L mdmExists3615-mdmPrims3615 ; offset to modem exists routine
|
|
DC.L mdmSetUp3615-mdmPrims3615 ; offset to modem set up routine
|
|
DC.L mdmTearDown3615-mdmPrims3615 ; offset to modem tear down routine
|
|
DC.L mdmName3615-mdmPrims3615 ; offset to modem name routine
|
|
DC.L mdmSndVol3615-mdmPrims3615 ; offset to modem sound volume routine
|
|
DC.L mdmSndHW3615-mdmPrims3615 ; offset to system HW arbitration routine
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmType3615
|
|
;
|
|
; Entry: a1 = modem primitive global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
; a0 = modem type
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Returns the modem type stored in global storage.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmType3615
|
|
WITH immg3615Rec
|
|
move.l ModemType(a1),a0 ; A0 -> modem type from private storage
|
|
moveq #noErr,d0 ; no error
|
|
rts
|
|
ENDWITH
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmPower3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = no error
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; The express modem on Optimus cannot be turned on and off like the express modem on the
|
|
; portables. Thus this routine disables interrupts from the modem to simulate the modem
|
|
; power being turned off, and enables interrupts from the modem to simulate the modem
|
|
; power being turned on.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmPower3615
|
|
WITH immg3615Rec, immgParamBlock
|
|
move.l a2,-(sp) ; save a2
|
|
movea.l ModemBase(a1),a2 ; base address of modem
|
|
move.b OptSndCtl(a2),d0 ; get the current status
|
|
bclr #bOptIntMask,d0 ; assume power on, unmask interrupts
|
|
tst.w immgCommand(a0) ; check power on or off ; <H10>
|
|
bne.s @commonExit
|
|
bset #bOptIntMask,d0 ; mask interrupts
|
|
@commonExit move.b d0,OptSndCtl(a2) ; set the status
|
|
move.l (sp)+,a2 ; restore a2
|
|
moveq #noErr,d0
|
|
rts
|
|
ENDWITH
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmWakeup3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Returns immgInvalidSelector error, since the express modem on Optimus does not currently
|
|
; support wake up on ring. There is no software to take advantage of the wake up on ring
|
|
; feature at the present time. This routine returns an error so that when software
|
|
; becomes available that can take advantage of wake up on ring, it can check the return
|
|
; result from this function to determine if the desired behavior has taken place.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmWakeup3615
|
|
WITH immg3615Rec
|
|
move.w #immgInvalidSelector,d0 ; <H8>
|
|
rts
|
|
ENDWITH
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmStatus3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Constructs status byte from various sources.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmStatus3615
|
|
WITH immgParamBlock
|
|
moveq #(1<<bPMMdmPower) | \ ; modem is on
|
|
(1<<bPMRingWakeUp) | \ ; ring wakeup is enabled
|
|
(1<<bPMMdmInstall),d0 ; modem is installed
|
|
btst.b #OptRingDet,OptMdmBase+OptSPIMdmCtl ; test if ring detect is set
|
|
beq.s @noRingDet
|
|
moveq #(1<<bPMMdmPower) | \ ; modem is on
|
|
(1<<bPMRingWakeUp) | \ ; ring wakeup is enabled
|
|
(1<<bPMMdmInstall) | \ ; modem is installed
|
|
(1<<bPMRingDet),d0 ; ring detect is set
|
|
@noRingDet move.w #1,immgLength(a0) ; set the length to one byte
|
|
move.l immgRBuffer(a0),a0 ; A0 -> pointer to receive buffer
|
|
move.b d0,(a0) ; put the status into the return buffer
|
|
move.w #noErr,d0 ; set error code
|
|
rts
|
|
ENDWITH
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmPrime3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Uses:
|
|
; D0: scratch register, result code
|
|
; D1: high word: scratch; low word: command number
|
|
; D2: scratch (by lower level routines)
|
|
; D3: scratch
|
|
; D4: scratch
|
|
; D5: scratch
|
|
; D6: high word: contents of status register; low word: scratch
|
|
; D7: stack base for poll stack
|
|
;
|
|
; A0: modem manager parameter block pointer
|
|
; A1: scratch, VIA 1 base
|
|
; A2: modem base address
|
|
; A3: scratch (by lower level routines, return address)
|
|
; A4: scratch (by lower level routines, return address)
|
|
; A5: pointer to immg3615Rec, not valid after UnloadPollStack
|
|
; A6: pointer to SCC channel A data register
|
|
; A7: stack pointer, pollstack pointer
|
|
;
|
|
; Sends and receives bytes to/from the modem.
|
|
;
|
|
; Processor interrupts are masked during this command. The SCC data is polled during the
|
|
; call and the data is stored on the stack. Great pains are taken to keep the stack clear
|
|
; for the SCC data. At the end of the call, the PollProc is called to remove the SCC data
|
|
; from the stack.
|
|
;
|
|
; Interrupts can be disabled by this routine for an indeterminate amount of time. In
|
|
; practice, the call takes no more than about 4ms. The time out value for the communication
|
|
; of one byte of data to or from the modem is 32ms. It is therefore theoretically possible
|
|
; that in a worst case scenario, say some hardware problem where the communication to and
|
|
; from the modem takes 31ms, and there are 100 bytes to receive from the modem, that
|
|
; interrupts would be disabled for 3.1sec! This problem is left to future authors of the
|
|
; primitive.
|
|
;
|
|
; SPI stands for Serial Port Interface, and is a standard interface specification for
|
|
; the Motorola 6805 microcontroller.
|
|
;
|
|
; There is no attempt by this primitive to recover from any errors that may be encountered
|
|
; during the sending or receiving of bytes to/from the modem. If an error does occur, it
|
|
; is reported, but the hardware may not be in the expected state.
|
|
;
|
|
; Pointers to the send and receive count tables are stored in the mdmSetUp routine above.
|
|
; This is done so that patching the tables is easy.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmPrime3615
|
|
immgrPollRegs REG D3/D4/D5/D6/A0/A1/A2/A4 ; registers to save across pollproc call
|
|
@numPollRegs EQU 4+4 ; number of registers to save across pollproc call
|
|
@savedRegs REG D1-D7/A0-A6 ; registers saved across this routine
|
|
|
|
movem.l @savedRegs,-(SP) ; save working registers
|
|
|
|
move.w sr,d6 ; save the entry SR in the upper half of D6
|
|
swap d6
|
|
|
|
WITH immgParamBlock
|
|
|
|
movea.l immg3615Rec.ModemBase(a1),a2 ; point to modem base address
|
|
movea.l a1,a5 ; save pointer to immg3615Rec
|
|
|
|
; disable interrupts during the time of this call
|
|
|
|
ori #HiIntMask,sr ; no interrupts
|
|
|
|
; set up for SCC polling...
|
|
|
|
lea -4*@numPollRegs(sp),sp ; allocate space for registers saved if we call PollProc
|
|
move.l sp,d7 ; point to the stack top for our SCC poll stack
|
|
|
|
movea.l SccRd,a6 ; point to the SCC channel A's data register <H26>
|
|
addq.w #aData,a6 ; <H26>
|
|
tst.l PollProc ; is a poll proc installed? <H52>
|
|
bne.s @WillPoll ; -> yes <H52>
|
|
|
|
; the offset +sccData is added to the address below because the routines that read the
|
|
; scc data out of the address subtract sccData from the base of the scc when reading data.
|
|
; See WaitSPIAckHi and WaitSPIAckLo below.
|
|
|
|
lea @NoPollSCC+sccData,a6 ; no, avoid collecting bytes no one will use <H52>
|
|
|
|
@WillPoll
|
|
|
|
; ----- send command and count ----
|
|
|
|
move.w immgCommand(a0),d3
|
|
move.w d3,d1
|
|
bsr SendSPI ; send command byte
|
|
bne.s @ImmgOpExit ; exit if error returned <H24>
|
|
|
|
movea.l immg3615Rec.SendTable(a5),a1 ; and get the send count table <H21>
|
|
move.w immgLength(a0),d5 ; pop the count into d5
|
|
bsr GetLenCount ; D0 -> number of bytes to send, -1 for dynamic
|
|
bpl.s @noCount ; if positive, no count
|
|
|
|
move.w d5,d1
|
|
bsr SendSPI ; send count byte
|
|
bne.s @ImmgOpExit ; exit if error returned <H24>
|
|
|
|
; ----- send data ----
|
|
|
|
@noCount movea.l immgSBuffer(a0),a1 ; get the pointer to the command's data bytes
|
|
moveq #0,d1 ; (set CCR for BEQ so DBNE below won't fall thru)
|
|
bra.s @StartSend
|
|
|
|
@SendData move.b (a1)+,d1 ; get the next data byte
|
|
bsr SendSPI ; and send it
|
|
@StartSend dbne d5,@SendData ; -> more bytes to send
|
|
bne.s @ImmgOpExit ; -> error
|
|
|
|
; ----- receive data -----
|
|
movea.l immg3615Rec.RecvTable(a5),a1 ; and get the receive count table <H21>
|
|
bsr GetLenCount ; D0 -> number of bytes to send, -1 for dynamic
|
|
move.b d1,d3
|
|
bmi.s @readReplyCount ; (<0)
|
|
cmp.b #1,d3 ; test against 1
|
|
ble.s @readData ; if ( =0 or =1 ) go to read
|
|
subq #1,d3 ; (>1) correct count
|
|
bra.s @readData ; if 0 or 1 go to read
|
|
|
|
@readReplyCount
|
|
bsr ReceiveSPI ; read first byte for receive count
|
|
bne.s @ImmgOpExit ; exit if error returned <H24>
|
|
move.b d1,d3 ; move count into d3
|
|
|
|
@readData ; d4 has receive byte count
|
|
movea.l immgRBuffer(a0),a1 ; a1 new points
|
|
move.w d3,immgLength(a0) ;
|
|
bra.s @StartReceive ; start receiving data
|
|
|
|
@ReceiveByte
|
|
bsr ReceiveSPI ; read a byte into d1
|
|
bne.s @ImmgOpExit ; -> error
|
|
move.b d1,(a1)+ ; move data byte into buffer
|
|
|
|
@StartReceive
|
|
dbra d3,@ReceiveByte ; -> more bytes to send
|
|
|
|
@ImmgOpExit
|
|
|
|
; check if any SCC bytes were collected so we can send them to the serial driver...
|
|
|
|
move.l d0,d4 ; save return result
|
|
movea.l VIA,a1 ; point to VIA1
|
|
bsr UnloadPollstack ; unload any SCC data stashed while interrupts were disabled
|
|
lea 4*@numPollRegs(sp),sp ; de-allocate PollProc saved register frame
|
|
move.l d4,d0 ; restore return result
|
|
|
|
; clean everything up...
|
|
|
|
swap d6
|
|
move.w d6,sr
|
|
tst.l d0 ; to set condition codes
|
|
|
|
@exit movem.l (sp)+,@savedRegs ; restore working registers
|
|
|
|
rts
|
|
|
|
ENDWITH
|
|
|
|
@NoPollSCC dc.w 0 ; A6 points here if no PollProc to avoid stack overflow <H52>
|
|
|
|
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ <H24>
|
|
; Routine: WaitSPIAckHi
|
|
;
|
|
; Input: a2.l - pointer to modem base
|
|
; a6 - pointer to serialpoll data area
|
|
;
|
|
; Destroys: d2,d1,a3
|
|
;
|
|
; Returns d0.b - 0 = ok, non-zero = error
|
|
;
|
|
; Function: wait for SPI ack high
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ <H24>
|
|
WaitSPIAckHi
|
|
move.l (sp)+,a3 ; pop return address into a3 <37>
|
|
move.w #32,d2 ; loop to max 32 msec
|
|
@nextmsec
|
|
move.w timedbra,d1 ; 1 msec count
|
|
@waitAckhi
|
|
btst.b #RxCA,-sccData(A6) ; SCC data available? <37>
|
|
beq.s @WaitLoop ; <37>
|
|
move.b (A6),-(SP) ; yes, push it on the stack <37>
|
|
@WaitLoop ; <37>
|
|
btst.b #OptSPIAck,OptSPIMdmCtl(a2) ; test ack
|
|
dbne d1,@waitAckhi ; loop for upto 1 msec
|
|
dbne d2,@nextmsec ; loop for d2 msec
|
|
seq d0 ; set result (d0 <> 0 = error), bit lo
|
|
tst.b d0 ; set the condition codes <H26>
|
|
jmp (a3) ; return through a3 <37>
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ <H24>
|
|
; Routine: WaitSPIAckLo
|
|
;
|
|
; Input: a2 - pointer to modem base
|
|
; a6 - pointer to serialpoll data area
|
|
;
|
|
; Destroys: d2,d1,a3
|
|
;
|
|
; Returns d0 - 0 = ok, non-zero = error
|
|
;
|
|
; Function: wait for SPI ack lo
|
|
;
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ <H24>
|
|
WaitSPIAckLo
|
|
move.l (sp)+,a3 ; pop return address into a3 <37>
|
|
move.w #32,d2 ; loop to max 32 msec
|
|
@nextmsec
|
|
move.w timedbra,d1 ; 1 msec count
|
|
@waitAckhi
|
|
btst.b #RxCA,-sccData(A6) ; SCC data available? <37>
|
|
beq.s @WaitLoop ; <37>
|
|
move.b (A6),-(SP) ; yes, push it on the stack <37>
|
|
@WaitLoop ; <37>
|
|
btst.b #OptSPIAck,OptSPIMdmCtl(a2) ; test ack
|
|
dbeq d1,@waitAckhi ; loop for upto 1 msec
|
|
dbeq d2,@nextmsec ; loop for d2 msec
|
|
sne d0 ; set result (d0 <> 0 = error), bit hi
|
|
tst.b d0 ; set the condition codes <H26>
|
|
jmp (a3) ; return through a3 <37>
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; Routine: SendSPI
|
|
;
|
|
; Input: a2.l - pointer to modem base
|
|
; a6 - pointer to serialpoll data area
|
|
; d1.b - byte to send
|
|
;
|
|
; Destroys: a4
|
|
; Destroys: d2,d1,a3 (by lower level routines)
|
|
;
|
|
; Returns d0.w - 0 = ok, non-zero = error
|
|
;
|
|
; Function: send a byte thru the SPI
|
|
;
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
SendSPI
|
|
move.l (sp)+,a4 ; pop return address into a4 <37>
|
|
swap d1 ; save the data byte in the hi work of d0
|
|
bsr.s WaitSPIAckHi ; (1) wait for pmgr idle <H24>
|
|
bne.s @error ; if bit low, error <H24>
|
|
|
|
;begin transaction
|
|
swap d1 ; get the data byte back
|
|
bset.b #OptLmpSPIDir,OptLmpSftCtl(a2) ; (2) set direction to output
|
|
move.b d1,OptSPISftReg(a2) ; (3) write data
|
|
bclr.b #OptSPIReq,OptSPIMdmCtl(a2) ; (4) assert data valid
|
|
bsr.s WaitSPIAckLo ; (5) --> modem shift data <H24>
|
|
; (6) wait for data accepted <H24>
|
|
bne.s @error ; if bit low, error <H24>
|
|
bset.b #OptSPIReq,OptSPIMdmCtl(a2) ; (7) clear data valid
|
|
|
|
move.w #noErr,d0 ; report no error
|
|
jmp (a4)
|
|
|
|
@error ; <H24>
|
|
bset.b #OptSPIReq,OptSPIMdmCtl(a2) ; (7) clear data valid <28>
|
|
move.w #immgSendStartErr,d0 ; report send error <H24>
|
|
jmp (a4)
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; Routine: ReceiveSPI
|
|
;
|
|
; Input: a2.l - pointer to modem base
|
|
; a6 - pointer to serialpoll data area
|
|
; d1.b - byte to send
|
|
;
|
|
; Destroys: a4
|
|
; Destroys: d2,a3 (by lower level routines)
|
|
;
|
|
; Returns d0.w - 0 = ok, non-zero = error
|
|
; d1.b - data byte read
|
|
;
|
|
; Function: read a byte from the spi
|
|
;
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
ReceiveSPI
|
|
move.l (sp)+,a4 ; pop return address into a4 <37>
|
|
bsr.s WaitSPIAckHi ; (1) wait for pmgr idle <H24>
|
|
bne.s @error ; if bit low, error <H24>
|
|
|
|
;begin transaction
|
|
bclr.b #OptLmpSPIDir,OptLmpSftCtl(a2) ; (2) set direction to input
|
|
bclr.b #OptSPIReq,OptSPIMdmCtl(a2) ; (3) (RFD) ready for data
|
|
bsr.s WaitSPIAckLo ; (4) acknowledge req <H24>
|
|
; (5) <-- modem shifting <H24>
|
|
bne.s @error ; if bit low, error <H24>
|
|
bset.b #OptSPIReq,OptSPIMdmCtl(a2) ; (6) acknowledge ack
|
|
|
|
bsr.s WaitSPIAckHi ; (7) wait (DAV) <H24>
|
|
bne.s @error ; if bit low, error <H24>
|
|
move.b OptSPISftReg(a2),d1 ; (8) read data
|
|
|
|
move.w #noErr,d0 ; report no error
|
|
jmp (a4)
|
|
|
|
@error
|
|
bset.b #OptSPIReq,OptSPIMdmCtl(a2) ; (7) clear data valid <28>
|
|
move.w #immgRecvStartErr,d0 ; mark as recieve error <H24>
|
|
jmp (a4)
|
|
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: UnloadPollstack
|
|
;
|
|
; Inputs: D7 -- pointer to top of poll stack
|
|
; A1 -- pointer to VIA1 base
|
|
; A6 -- pointer to SCC channel A data register
|
|
; SP -- pointer to bottom of poll stack
|
|
;
|
|
; Outputs: D7 -- pointer to top of poll stack
|
|
; A1 -- pointer to VIA1 base
|
|
; A6 -- pointer to SCC channel A data register
|
|
; SP -- pointer to top of poll stack
|
|
;
|
|
; Trashes: D0,D1,D2,A3,A4,A5
|
|
;
|
|
; Function: calls the poll proc to unload any bytes stashed from SCC
|
|
; port A while interrupts were disabled
|
|
;_______________________________________________________________________
|
|
|
|
UnloadPollstack
|
|
movea.l (sp)+,A4 ; pop the return address
|
|
cmpa.l d7,sp ; is there any poll data?
|
|
beq.s @NoSCCData ; -> no
|
|
move.l PollProc,d0 ; is there a poll proc?
|
|
beq.s @NoPollProc ; -> no
|
|
move.l d7,PollStack ; stuff the PollStack
|
|
|
|
movea.l d7,a3
|
|
movem.l immgrPollRegs,(a3) ; save regs while calling poll proc W/O USING STACK
|
|
|
|
lea vBufA(a1),a5 ; point to the register with the SCC WR/REQ bit in VIA 1<H26>
|
|
|
|
movea.l d0,a3
|
|
jsr (a3) ; run the poll proc
|
|
|
|
movea.l d7,a3
|
|
movem.l (a3),immgrPollRegs ; restore our registers
|
|
@NoPollProc movea.l d7,sp ; toss any bytes left on the pollstack <H26>
|
|
@NoSCCData jmp (a4)
|
|
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSndCtl3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Hit the bit in the modem sound control register to turn sound on or off. Use sound
|
|
; primitives to set the sound input source and the play thru volume.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSndCtl3615
|
|
sndInvalidSrc EQU $ff ; invalid sound input source
|
|
|
|
WITH immg3615Rec, immgParamBlock, ExpandMemRec, SoundIOHeader
|
|
|
|
@savedRegs REG d1 ; registers to save over call
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
move.w immgCommand(a0),d1 ; D1 -> sound on or off command ; <H10>
|
|
cmp.w PreviousCmd(a1),d1 ; make sure that we are doing the opposite of what has been done ; <H10>
|
|
beq.s @done ; if the same, that means sound on request ; <H10>
|
|
; with sound on already, or sound off request; <H10>
|
|
; with sound off already : <H10>
|
|
|
|
move.w d1,PreviousCmd(a1) ; save the command being executed ; <H10>
|
|
|
|
move.b OptMdmBase+OptSndCtl,d0 ; pick up the current state
|
|
bclr #bOptSndMask,d0 ; assume modem sound off
|
|
cmp.w #immgSndOn,d1 ; check if sound should go on
|
|
bne.s @continue ; if not, continue
|
|
bset #bOptSndMask,d0 ; turn modem sound on
|
|
@continue move.b d0,OptMdmBase+OptSndCtl ; make it so!
|
|
|
|
cmp.w #immgSndOn,d1 ; check if sound should go on ; <H3>
|
|
beq.s @saveIt ; if sound on, save the current state ; <H3>
|
|
move.b SndInputSrc(a1),d0 ; no, restore sound input
|
|
move.b PlayThruVol(a1),d1 ; D1 -> saved playthrough volume
|
|
exg d0,d1 ; D0 -> playthrough volume
|
|
bsr SetPlayThru ; reset playthrough volume first
|
|
exg d0,d1 ; D0 -> sound input source
|
|
bsr SetInputSrc ; reset input source last
|
|
bra.s @done ; continue to just set sound input ; <H3>
|
|
|
|
@saveIt movea.l ([ExpandMem],emSndPrimitives),a0 ; <H3>
|
|
move.b UserVolume(a0),PlayThruVol(a1) ; save playthrough volume setting
|
|
move.b SDVolume,d1 ; D1 -> playthrough volume
|
|
tst.l sndInputSource*4(a0) ; is there a handler? ; <H3>
|
|
beq.s @done ; no, just exit ; <H3>
|
|
move.l sndInputSource*4(a0),a0 ; <H3>
|
|
jsr (a0) ; call the ioprimitive ; <H3>
|
|
|
|
; check that the source that was returned is not invalid. The primitives for Optimus
|
|
; currently return sndInvalidSrc if the sound input source is undefined (not yet been
|
|
; set). Unfortunately, if we try to restore the sound input source to the value
|
|
; sndInvalidSrc, DFAC II hangs.
|
|
|
|
cmp.b #sndInvalidSrc,d0 ; check for garbage ; <H3>
|
|
bne.s @okToSave ; if not garbage, save it ; <H3>
|
|
moveq #0,d0 ; assume no input ; <H3>
|
|
@okToSave move.b d0,SndInputSrc(a1) ; save previous input source ; <H3>
|
|
moveq #sndAuxiliary,d0 ; set modem sound on ; <H3>
|
|
bsr SetInputSrc ; set input source first
|
|
exg d0,d1 ; D0 -> playthrough volume
|
|
bsr SetPlayThru ; set playthrough last
|
|
|
|
@done move.w #noErr,d0
|
|
movem.l (sp)+,@savedRegs ; restore registers
|
|
@exit rts
|
|
|
|
SetPlayThru movea.l ([ExpandMem],emSndPrimitives),a0 ; <H3>
|
|
tst.l sndPlayThruVol*4(a0) ; is there a handler? ; <H3>
|
|
beq.s @done ; no, just exit ; <H3>
|
|
move.l sndPlayThruVol*4(a0),a0
|
|
jsr (a0) ; call the ioprimitive
|
|
@done rts
|
|
|
|
SetInputSrc movea.l ([ExpandMem],emSndPrimitives),a0 ; <H3>
|
|
tst.l sndInputSelect*4(a0) ; is there a handler? ; <H3>
|
|
beq.s @done ; no, just exit ; <H3>
|
|
move.l sndInputSelect*4(a0),a0 ; <H3>
|
|
jsr (a0) ; call the ioprimitive ; <H3>
|
|
@done rts
|
|
ENDWITH
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmExists3615
|
|
;
|
|
; Entry: none
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Check if a 3615 modem is installed in the box.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmExists3615
|
|
|
|
@savedRegs REG d1/a2 ; registers to save over call
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
; now, how to tell if a modem is installed? Unfortunately, we do NOT get a
|
|
; bus error reading the modem register space (since this is ethernet prom space).
|
|
; This means that we must write a register in the modem and read it back to determine
|
|
; if there is anything at that address that will latch the data we send.
|
|
|
|
move.b BIOS_Config2+BIOSAddr,d0 ; get BIOS config 2 reg contents
|
|
bset #bBIOSIOCSTime,d0 ; set IO_CS_Time to be asserted on writes
|
|
move.b d0,BIOS_Config2+BIOSAddr ; put byte into configuration reg
|
|
movea.l #OptMdmBase,a2 ; get base address of modem
|
|
move.b OptSndCtl(a2),d0 ; contents of interrupt req reg
|
|
not.b d0 ; invert bits
|
|
bset #bOptIntMask,d0 ; never unmask interrupts unless handler is installed
|
|
move.b d0,OptSndCtl(a2) ; write invert out to int req reg
|
|
not.b d0 ; put back original
|
|
bset #bOptIntMask,d0 ; never unmask interrupts unless handler is installed
|
|
|
|
; Do a write to the modem ID reg so that the bus does not float to the thing just
|
|
; written to the register. MdmID is a safe place to write arbitrary data. If the
|
|
; byte written to MdmID floats on the next read, we will conclude that there is no
|
|
; modem installed (due to the eor).
|
|
|
|
move.b d0,OptMdmBase+OptMdmIDReg ; Place bad data on the bus ; <H7>
|
|
|
|
move.b OptSndCtl(a2),d1 ; read back contents
|
|
eor.b d1,d0 ; to test if bit for int mask latched
|
|
btst.l #bOptSndMask,d0 ; check int mask bit
|
|
beq.w @noModem ; no modem!
|
|
|
|
move.w #noErr,d0 ; indicate modem exists
|
|
|
|
@exit move.b BIOS_Config2+BIOSAddr,d1 ; get BIOS config 2 reg contents
|
|
bclr #bBIOSIOCSTime,d1 ; set IO_CS_Time to not be asserted on writes
|
|
move.b d1,BIOS_Config2+BIOSAddr ; put byte into configuration reg
|
|
|
|
movem.l (sp)+,@savedRegs ; restore registers
|
|
rts
|
|
|
|
@noModem move.w #immgNoBoardErr,d0 ; indicate no board
|
|
bra.s @exit
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSetUp3615
|
|
;
|
|
; Entry: none
|
|
;
|
|
; Exit: d0 = result code
|
|
; a0 = pointer to modem primitives globals
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Set up the primitives for the 3615 modem.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSetUp3615
|
|
@savedRegs REG a2-a3
|
|
|
|
movem.l @savedRegs,-(sp) ; save registers
|
|
|
|
WITH immg3615Rec, immg3615SlotQEl
|
|
|
|
; allocate private storage for modem primitives
|
|
|
|
move.l #immg3615Rec.size,d0 ; get size of private storage
|
|
_NewPtr ,SYS,CLEAR ; get a pointer in the system heap ; <H10>
|
|
tst.w d0 ; check for errors
|
|
bne.w @error1 ; if no memory, cannot continue
|
|
movea.l a0,a3 ; a3 = pointer to private storage
|
|
|
|
movea.l #OptMdmBase,a2 ; get base address of modem
|
|
move.l a2,ModemBase(a3) ; store base address
|
|
|
|
lea cmdCounts,a0 ; A0 -> pointer to command send count table for mdmPrime
|
|
move.l a0,SendTable(a3) ; store command send count table
|
|
lea replyCounts,a0 ; A0 -> pointer to receive count table
|
|
move.l a0,RecvTable(a3) ; store receive count table
|
|
|
|
moveq #0,d0 ; clear D0
|
|
move.b OptMdmIDReg(a2),d0 ; get modem ID
|
|
move.l d0,ModemType(a3) ; store the modem type in private storage
|
|
|
|
move.b #(1<<bOptIntMask),OptSndCtl(a2) ; set modem interrupt bit, clear speaker sound bit ; <H10>
|
|
|
|
; The bit in the via2 is set for a slot 9 interrupt whenever the modem interrupts, even
|
|
; though the modem interrupt comes in at level 3. If the process of a level 2 interrupt
|
|
; has already begun, the slot 9 interrupt will attempt to be handled, which causes a
|
|
; problem. Is there anything that we should be aware of that might bite us in the butt
|
|
; later since we are installing a minimal slot 9 interrupt handler? How can the slot 9
|
|
; handler actually tell that the modem caused the interrupt and the interrupt is not
|
|
; actually a spurious one?
|
|
|
|
move.l #immg3615SlotQEl.size,d0 ; size of 3615 slot queue element (modified)
|
|
_NewPtr ,SYS ; get a slot queue element in the system heap
|
|
tst.w d0 ; check for valid pointer
|
|
bne.s @error2 ; cannot go on like this...
|
|
|
|
move.l a0,Slot9Addr(a3) ; save pointer to slot 9 handler
|
|
move.w #0,sqPrio(a0) ; set priority to 0, the lowest priority
|
|
move.w #sIQType,sqType(a0) ; set type to slot interrupt type
|
|
lea sqInt9Count(a0),a2 ; get pointer to count buffer
|
|
move.l #0,(a2) ; initialize counter
|
|
move.l a2,sqParm(a0) ; set up optional a1 pointer to the counter space
|
|
lea Slot9Handler,a2 ; get the address of the slot interrupt handler
|
|
move.l a2,sqAddr(a0) ; put pointer into slot queue element routine address
|
|
move.l #OptHackSlotNum,d0 ; install the handler in slot 9
|
|
_SIntInstall
|
|
tst.w d0 ; any error?
|
|
bne.s @error3 ; we just can't go on...
|
|
|
|
move.b BIOS_Config2+BIOSAddr,d0 ; get BIOS config 2 reg contents
|
|
ori.b #(1<<bBIOSENETIRQLVL) | \ ; set irq level to level 3
|
|
(1<<bBIOSIOCSTime),d0 ; set IO_CS_Time to be asserted on writes
|
|
move.b d0,BIOS_Config2+BIOSAddr ; put byte into configuration reg
|
|
|
|
move.l ModemBase(a3),a2 ; A2 -> modem base address ; <H10>
|
|
move.b #(1<<bOptIntMask),OptSndCtl(a2) ; set modem interrupt bit, clear speaker sound bit ; <H10>
|
|
|
|
movea.l a3,a0 ; return pointer to primitives globals
|
|
moveq #noErr,d0 ; no error
|
|
|
|
@exit movem.l (sp)+,@savedRegs ; restore registers
|
|
rts
|
|
|
|
; have allocated a slot queue element (in globals)
|
|
@error3 movea.l Slot9Addr(a3),a0 ; A0 -> pointer to slot queue element
|
|
_DisposPtr ; take out the trash
|
|
|
|
; have allocated pointer to globals in A3
|
|
@error2 movea.l a3,a0 ; gotta have it
|
|
_DisposPtr ; gotta get rid of it
|
|
|
|
; indicate initialization error
|
|
@error1 move.w #immgInitError,d0 ; bad...
|
|
bra.s @exit
|
|
|
|
ENDWITH
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: Slot 9 handler
|
|
;
|
|
; Inputs: a1 = pointer to a count buffer
|
|
;
|
|
; Outputs: d0 = 0 if interrupt not handled, 1 if interrupt handled
|
|
;
|
|
; Trashes: a0
|
|
;
|
|
; Function: a simple slot 9 interrupt handler. The reason this routine
|
|
; is necessary is twofold:
|
|
; 1. There is a bug in PrimeTime that sets the VIA2 port A data register
|
|
; bit that signifies a slot 9 interrupt has occurred when the modem
|
|
; signals an interrupt on level 3.
|
|
; 2. There is a bug in the interrupt handler for the Elan card that leaves
|
|
; the interrupt mask bits in the processor status register (SR) set
|
|
; to mask level 4 or 6, which, in combination with above bug, causes
|
|
; the slot manager slot interrupt code to go into an infinite loop under
|
|
; the following circumstance:
|
|
; The processor is handling a level 2 interrupt for the Elan card,
|
|
; and while it is in the Elan interrupt service routine, a modem
|
|
; interrupt comes in, setting the VIA2 port A data register bit.
|
|
; The Elan interrupt routine exits, but leaves the SR mask set to
|
|
; 4 (or 6). The slot manager, wanting to make sure that all slot
|
|
; interrupts have been handled, reads the VIA2 port A data register,
|
|
; which indicates that a slot 9 interrupt is requested. The slot 9
|
|
; interrupt handler is entered. If the handler for slot 9 does not
|
|
; lower the SR mask to 2 (to allow the real level 3 interrupt to occur
|
|
; and be serviced), an infinite loop results.
|
|
;_______________________________________________________________________
|
|
|
|
ALIGN 2
|
|
Slot9Handler
|
|
add.l #1,(a1) ; bump counter of how many times in this routine
|
|
move sr,d0 ; get the status register to check for interrupt mask
|
|
andi.w #statMaskBits,d0 ; mask off interrupt mask information
|
|
cmpi.w #level3Bits,d0 ; check for int mask > 2
|
|
blo.s @noProblem ; no problem with interrupt mask
|
|
move sr,d0 ; save the status register
|
|
swap d0 ; put saved SR in high word
|
|
move sr,d0 ; get SR to lower mask
|
|
andi.w #~statMaskBits,d0 ; clear all status mask bits
|
|
ori.w #level2Bits,d0 ; make interrupt mask level 2
|
|
move d0,sr ; lower priority mask temporarily
|
|
swap d0 ; get the saved sr -- the level 3 interrupt should occur here!
|
|
move d0,sr ; restore interrupt mask level
|
|
@noProblem move.l VIA2RBVOSS,a0 ; get via2 base address
|
|
move.b vBufA(a0),d0 ; read via 2 data register
|
|
andi.b #(1<<v2IRQ1),d0 ; mask off slot 9 interrupt bit (will be zero if interrupt not handled, 1 if handled)
|
|
rts
|
|
|
|
ALIGN 2
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmTearDown3615
|
|
;
|
|
; Entry: a1 = pointer to modem primitives globals
|
|
;
|
|
; Exit: d0 = no error
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Deallocates everything that the set up routine allocated and sets PrimeTime so that
|
|
; no modem interrupts are generated.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmTearDown3615
|
|
WITH immg3615Rec
|
|
|
|
; make sure BIOS does not generate level three interrupts
|
|
|
|
move.b BIOS_Config2+BIOSAddr,d0 ; get BIOS config 2 reg contents
|
|
bclr.l #bBIOSENETIRQLVL,d0 ; set irq level to level 2
|
|
bclr.l #bBIOSIOCSTime,d0 ; set IO_CS_Time to not be asserted on writes
|
|
move.b d0,BIOS_Config2+BIOSAddr ; put byte into configuration reg
|
|
|
|
; remove slot 9 interrupt handler
|
|
|
|
move.l Slot9Addr(a1),a0 ; A0 -> pointer to slot queue element
|
|
move.l #OptHackSlotNum,d0 ; remove the handler from slot 9
|
|
_SIntRemove ; get rid of it if it is there
|
|
|
|
; deallocate slot queue element
|
|
|
|
move.l Slot9Addr(a1),a0 ; A0 -> pointer to slot queue element
|
|
_DisposPtr
|
|
|
|
; deallocate private storage for modem primitives
|
|
|
|
movea.l a1,a0 ; A0 -> pointer to private storage
|
|
_DisposPtr
|
|
|
|
moveq #noErr,d0 ; no error
|
|
|
|
@exit rts
|
|
|
|
ENDWITH
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmName3615
|
|
;
|
|
; Entry: a0 = pointer to string buffer
|
|
; a1 = pointer to modem primitives globals
|
|
;
|
|
; Exit: d0 = no error
|
|
; a0 = pointer to null terminated string
|
|
;
|
|
; Trashes: A1
|
|
;
|
|
; Returns the name of the modem.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmName3615
|
|
move.l a0,-(sp) ; save pointer
|
|
|
|
movea.l a0,a1 ; destination
|
|
lea @modemName,a0 ; source (skip over length byte)
|
|
@loop move.b (a0)+,(a1)+ ; copy one byte
|
|
bne.s @loop ; keep copying until null terminal byte is copied
|
|
|
|
movea.l (sp)+,a0 ; return modem name in A0
|
|
moveq #noErr,d0 ; no error
|
|
|
|
@exit rts
|
|
|
|
@modemName dc.b 'Express Modem'
|
|
dc.b 0
|
|
|
|
ALIGN 2
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSndVol3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Returns immgInvalidSelector error, since the express modem on Optimus does not currently
|
|
; support relative sound volume control. This routine returns an error so that when software
|
|
; becomes available that can take advantage of sound volume, it can check the return
|
|
; result from this function to determine if the desired behavior has taken place.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSndVol3615
|
|
WITH immg3615Rec
|
|
move.w #immgInvalidSelector,d0
|
|
rts
|
|
ENDWITH
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; mdmSndHW3615
|
|
;
|
|
; Entry: a0 = modem manager param block pointer
|
|
; a1 = modem primitives global pointer
|
|
;
|
|
; Exit: d0 = result code
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Returns immgInvalidSelector error, since the express modem on Optimus does not currently
|
|
; support system sound hardware arbitration. This routine returns an error so that if software
|
|
; becomes available that arbitrates for the hardware, it can check the return
|
|
; result from this function to determine if the desired behavior has taken place.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
mdmSndHW3615
|
|
WITH immg3615Rec
|
|
move.w #immgInvalidSelector,d0
|
|
rts
|
|
ENDWITH
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
; GetLenCount
|
|
;
|
|
; Entry: d3.w = command for count
|
|
; a1 = pointer to count table
|
|
;
|
|
; Exit: d1.b = count
|
|
; condition codes set on d1.b
|
|
;
|
|
; Trashes: a1
|
|
;
|
|
; Looks up count for command in d3 in table.
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
GetLenCount
|
|
@saveRegs REG d3/a0 ; registers to save
|
|
|
|
movem.l @saveRegs,-(sp) ; save registers
|
|
clr.w d1 ; clear out the low word
|
|
|
|
lea @RangeTable,a0 ; A0 -> pointer to range table
|
|
@checkLoop move.b (a0)+,d1 ; D1 -> normalizing byte
|
|
beq.s @noCount ; no more ranges, no count...
|
|
sub.b d1,d3 ; normalize d3 to range
|
|
bmi.s @noCount ; if less than, no count
|
|
move.b (a0)+,d1 ; D1 -> range size
|
|
cmp.b d1,d3 ; check if d3 is in range
|
|
blt.s @lookup ; yep, go look it up
|
|
adda.w d1,a1 ; increment table pointer to next range
|
|
bra.s @checkLoop ; nope, continue checking...
|
|
|
|
@lookup move.b (a1,d3.w),d1 ; D1 -> count
|
|
|
|
@exit movem.l (sp)+,@saveRegs ; restore registers
|
|
rts
|
|
|
|
@noCount move.b #$ff,d1 ; D1 -> no count
|
|
bra.s @exit
|
|
|
|
@RangeTable
|
|
dc.b $50,$10 ; cmd range $50-$5f
|
|
dc.b $20,$10 ; cmd range $70-$7f
|
|
dc.b $30,$10 ; cmd range $a0-$af
|
|
dc.w 0
|
|
|
|
;_______________________________________________________________________________________
|
|
;
|
|
; This table is used to determine if the 680x0 needs to send a count byte to the modem.
|
|
; A positive value means that the count is known by both sides, and so it is not sent.
|
|
; A negative value means that the command can send variable amounts of data, so the
|
|
; count byte specified in the modem manager param block needs to be sent.
|
|
;
|
|
; Unused commands will be marked as expecting the count to be sent so that commands
|
|
; may be added without having to change the ROM.
|
|
|
|
cmdCounts DC.B 1 ; [$50] Set Internal Modem Control Bits
|
|
DC.B 0 ; [$51] Clear FIFOs
|
|
DC.B 2 ; [$52] Set FIFO Interrupt Marks
|
|
DC.B 2 ; [$53] Set FIFO Sizes
|
|
DC.B -1 ; [$54] Write Data to Modem
|
|
DC.B 1 ; [$55] Set Data Mode
|
|
DC.B 3 ; [$56] Set Flow Control Mode <H55>
|
|
DC.B 1 ; [$57] Set DAA control lines <H54>
|
|
DC.B 0 ; [$58] Read Internal Modem Status
|
|
DC.B 1 ; [$59] Get DAA Identification <H55>
|
|
DC.B 0 ; [$5A] Get FIFO Counts
|
|
DC.B 0 ; [$5B] Get Maximum FIFO Sizes
|
|
DC.B 0 ; [$5C] Read Data From Modem
|
|
DC.B -1 ; [$5D] General Purpose modem command (modem dependent) <H58>
|
|
DC.B -1 ; [$5E] -
|
|
DC.B -1 ; [$5F] -
|
|
|
|
DC.B 1 ; [$70] Set One-Second Interrupt
|
|
DC.B 1 ; [$71] Modem Interrupt Control
|
|
DC.B 1 ; [$72] Set Modem Interrupt
|
|
DC.B -1 ; [$73] -
|
|
DC.B -1 ; [$74] -
|
|
DC.B -1 ; [$75] -
|
|
DC.B -1 ; [$76] -
|
|
DC.B -1 ; [$77] -
|
|
DC.B 0 ; [$78] Read Interrupt Flag Register.
|
|
DC.B 0 ; [$79] Read Modem Interrupt Data
|
|
DC.B -1 ; [$7A] -
|
|
DC.B -1 ; [$7B] -
|
|
DC.B -1 ; [$7C] -
|
|
DC.B -1 ; [$7D] -
|
|
DC.B 4 ; [$7E] Enter Shutdown Mode
|
|
DC.B 4 ; [$7F] Enter Sleep Mode
|
|
|
|
DC.B 2 ; [$A0] Write Modem Register
|
|
DC.B 2 ; [$A1] Clear Modem Register Bits
|
|
DC.B 2 ; [$A2] Set Modem Register Bits
|
|
DC.B 4 ; [$A3] Write DSP RAM
|
|
DC.B -1 ; [$A4] Set Filter Coefficients
|
|
DC.B 0 ; [$A5] Reset Modem
|
|
DC.B -1 ; [$A6] -
|
|
DC.B -1 ; [$A7] -
|
|
DC.B 1 ; [$A8] Read Modem Register
|
|
DC.B 1 ; [$A9] Send Break
|
|
DC.B 3 ; [$AA] Dial Digit
|
|
DC.B 2 ; [$AB] Read DSP RAM
|
|
DC.B -1 ; [$AC] -
|
|
DC.B -1 ; [$AD] -
|
|
DC.B -1 ; [$AE] -
|
|
DC.B -1 ; [$AF] -
|
|
|
|
|
|
; This table is used to determine how the 680x0 needs to handle the reply:
|
|
;
|
|
; =0: no reply should be expected.
|
|
; =1: only a reply byte will be sent (this is a special case for a couple of commands)
|
|
; <0: a reply is expected and the modem will send a count byte.
|
|
; >1: a reply is expected and the modem will not send a count byte,
|
|
; but the count to return in the modem manager param block will be (value-1).
|
|
;
|
|
; Unused commands in the range $x8 to $xF will be marked as expecting a reply (with count)
|
|
; so that commands may be added without having to change the ROM.
|
|
|
|
replyCounts DC.B 0 ; [$50] Set Internal Modem Control Bits
|
|
DC.B 0 ; [$51] Clear FIFOs
|
|
DC.B 0 ; [$52] Set FIFO Interrupt Marks
|
|
DC.B 0 ; [$53] Set FIFO Sizes
|
|
DC.B 0 ; [$54] Write Data to Modem
|
|
DC.B 0 ; [$55] Set Data Mode
|
|
DC.B 0 ; [$56] Set Flow Control Mode
|
|
DC.B 0 ; [$57] Set DAA control lines <H54>
|
|
DC.B 1+1 ; [$58] Read Internal Modem Status
|
|
DC.B 0 ; [$59] Get DAA Identification <H55>
|
|
DC.B 2+1 ; [$5A] Get FIFO Counts
|
|
DC.B 2+1 ; [$5B] Get Maximum FIFO Sizes
|
|
DC.B -1 ; [$5C] Read Data From Modem
|
|
DC.B -1 ; [$5D] General Purpose modem command (modem dependent) <H58>
|
|
DC.B -1 ; [$5E] -
|
|
DC.B -1 ; [$5F] -
|
|
|
|
DC.B 0 ; [$70] Set One-Second Interrupt
|
|
DC.B 0 ; [$71] Modem Interrupt Control
|
|
DC.B 0 ; [$72] Set Modem Interrupt
|
|
DC.B 0 ; [$73] -
|
|
DC.B 0 ; [$74] -
|
|
DC.B 0 ; [$75] -
|
|
DC.B 0 ; [$76] -
|
|
DC.B 0 ; [$77] -
|
|
DC.B -1 ; [$78] Read Interrupt Flag Register.
|
|
DC.B -1 ; [$79] Read Modem Interrupt Data
|
|
DC.B -1 ; [$7A] -
|
|
DC.B -1 ; [$7B] -
|
|
DC.B -1 ; [$7C] -
|
|
DC.B -1 ; [$7D] -
|
|
DC.B 0+1 ; [$7E] Enter Shutdown Mode
|
|
DC.B 0+1 ; [$7F] Enter Sleep Mode
|
|
|
|
DC.B 0 ; [$A0] Write Modem Register
|
|
DC.B 0 ; [$A1] Clear Modem Register Bits
|
|
DC.B 0 ; [$A2] Set Modem Register Bits
|
|
DC.B 0 ; [$A3] Write DSP RAM
|
|
DC.B 0 ; [$A4] Set Filter Coefficients
|
|
DC.B 0 ; [$A5] Reset Modem
|
|
DC.B 0 ; [$A6] -
|
|
DC.B 0 ; [$A7] -
|
|
DC.B 1+1 ; [$A8] Read Modem Register
|
|
DC.B 0 ; [$A9] Send Break
|
|
DC.B 0 ; [$AA] Dial Digit
|
|
DC.B 0 ; [$AB] Read DSP RAM
|
|
DC.B -1 ; [$AC] -
|
|
DC.B -1 ; [$AD] -
|
|
DC.B -1 ; [$AE] -
|
|
DC.B -1 ; [$AF] -
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; END OPTIMUS MODEM PRIMITIVES
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
|
|
|
|
End |