sys7.1-doc-wip/OS/IoPrimitives/PowerMgrPrimitives.a
2019-07-27 22:37:48 +08:00

5195 lines
241 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: PowerMgrPrimitives.a
;
; Contains: low-level routines for managing Power Management tasks
;
; Written by: Helder J. Ramalho
;
; Copyright: © 1992-1993 by Apple Computer, Inc. All rights reserved.
;
; This file is used in these builds: ROM
;
; Change History (most recent first):
;
; <SM8> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines.
; <SM7> 9/17/93 KH I'm not Eva (EH), but this BBS installation is apparently
; screwed up.
; <SM6> 9/17/93 SKH Fix a bug with sleep. Don't use A3 to acces PMgr globals, use
; A2. (SaveSleepInfo)
; <SM5> 8/4/93 JDR Private sound defines were moved to SoundPrivate.a.
; <SM4> 01-12-93 jmp Changed name from drHwDBLite to the more appropriate drHwGSC.
; <SM3> 11/20/92 SWC Rolled in the rest of the Horror changes.
; <H44> 8/13/92 SWC Changed GetExtLevel to change warning levels at the 1/3 and 2/3
; levels instead of at the x/4 levels so we get better spaced
; warnings.
; <H43> 8/4/92 SWC Save and restore the current GrafPort around the call to
; PaintBehind since PaintBehind will clobber it. This was causing
; the screen to be incorrectly updated (portions remained gray).
; <H42> 7/27/92 SWC Point to the correct SendSleep routine for DBLite (we
; distinguish between a normal and low power sleep).
; <H41> 7/23/92 SWC Fixed a bug in GetExtLevel that was keeping us from displaying
; low power messages.
; <H40> 7/22/92 SWC In SaveMSC, turn on IOClk before we go to sleep in case a bar is
; added during sleep so that the clock will be running as soon as
; power is turned back on. If it turns out no bar is attached, the
; Docking Manager will turn this back off.
; <H39> 7/14/92 ag Change the LeadScaledBattery routine to use globals and avoid
; hitting the power manager. Instead of current battery level,
; use averaged battery level.
; <H38> 7/14/92 djw (HJR) Remove NiagraChkIdle since it is not used.
; <H37> 7/14/92 SWC Hopefully I finally got the scaled battery stuff working (those
; Dart guys will be mighty pissed if we need to do a patch...).
; <H36> 7/14/92 HJR Modify dimming so that a screen update will only occur if some
; device supported the LowPwrSelect control call.
; <H35> 7/13/92 HJR Fix a bug in Dimming where if External Monitor is startup
; device, internal display does not unblank itself after dimming.
; Problem was that A0=IOPB was being trashed by PaletteDispatch.
; <H34> 7/13/92 HJR Rewrote External monitor alerts so that if an External Monitor
; Alert is displayed, the charger state will not remove alert.
; Added ChkDimming so that DBlite may use it more readily.
; <H33> 7/13/92 ag Added constants to the info tables for delay time before shorted
; battery dialog and delta battery warn level if external monitor
; is being used.
; <H32> 7/11/92 HJR Rewrote VidLowPwrSelect so that it runs throught the device list
; and powers down all available screens. Cleaned up things here
; and there.
; <H31> 7/10/92 ag added modem primitive tables and routines. added vectorize
; shutdown with retry.
; <H30> 7/1/92 ag Clear sound power control before turning on power amps.
; <H29> 7/1/92 ag Add code to turn off power to sound circuits controlled by ponti
; asic during sleep. Added power amplifiers controls to niagra
; sleep and wake routines.
; <H28> 6/30/92 HJR In SaveGSC and RestoreGSC, call the driver to Blank the screen
; on going to sleep and grey the screen on wakeup.
; <H27> 6/25/92 SWC Fixed the clamshell logic (was crashing if a docking bar
; prevented sleep). We no longer shutdown on clamshell close since
; that had a lot of problems. Upped the padding size to 8K since
; we're getting full (and more stuff is expected. :)
; <H26> 6/11/92 djw Modify PostUserNmMsg to accept completion routine parameter.
; Add code to check for posting a warning msg based on a flag set
; by the external video's primaryInit (if no charger attached) in
; NiagraRunIdleRoutineProc.
; <H25> 6/10/92 HJR Disable GDevice when dimming and fix bug where if external
; device is main device, bus error occurs after dimming.
; <H24> 6/9/92 ag change the batman save and restore code the the one used on
; terror. The order which things are done is very critical. if you
; must change the code, do so carefully.
; <H23> 6/5/92 SWC Finished up the scaled battery info routines.
; <H22> 6/2/92 djw Added check for external video without a charger in
; NiagraRunIdleRoutineProc. If condition found, post alert to the
; user. Added PostUserNmMsg utility routine.
; <H21> 6/1/92 HJR Disable GDevice if we are powering down the device.
; <H20> 5/19/92 HJR Generalized IdleMindTable with RunIdleRoutines so that various
; miscellaneous routines can be localized. Add
; NiagraRunIdleRoutineProc which now check whether to power down
; screens.
; <H19> 5/15/92 SWC Added the battery and sound monitoring VBL tasks to the list of
; primitives for each machine, and moved SndWatch and
; SndWatchPonti here from PowerMgr.a.
; <H18> 5/8/92 SWC Fixed a copy/paste typo in the MSC table that could cause a
; crash. Removed CPUSpeedNiagraRead since it's no longer used.
; <H17> 5/7/92 HJR Added primitives for WakeScreenRefresh and necessary code for
; VSCPowerSelect. Rewrote CPUSpeedNiagra to that it matches
; hardware. Blank GSC during wakeup.
; <H16> 5/7/92 ag Added softshutdown to Dartanian timeout checks.
; <H15> 5/7/92 SWC Added primitives to return a scaled battery level so the Battery
; DA, etc., won't have to be rev'd each time we do a new portable.
; Added a check to ChkHDSpinDown to prevent the hard disk from
; being spun down if we're connected to a docking station (AC
; power is assumed).
; <SM2> 11/19/92 SWC Exported the primitives tables so they can be used in
; UniversalTables.a. Changed ShutdownEqu.a->Shutdown.a.
; <1> 5/17/92 kc first checked in
; <SM0> 5/2/92 kc Roll in Horror. Comments follow:
; <H14> 4/24/92 HJR Updated NiagraChkIdle for current state of hardware. Changed
; PRAM base in NiagraPrimInfo to $46 since slot E is now needed
; for VSC.
; <H13> 4/17/92 SWC Added a check to GetExtLevel to see if the charger is connected
; since the returned battery voltage will be zero if we're running
; without a battery (causing the system to go to sleep all the
; time).
; <H12> 4/13/92 SWC Modified GetExtLevel to actually check for the existance of a
; battery. Zeroed the MSC default battery warning level values
; since they'll change depending on what kind of battery is
; connected. The PMGR will determine what these should be each
; time a new battery type is installed.
; <H11> 4/8/92 SWC Fixed a bug in the clamshell switch check.
; <H10> 3/20/92 SWC Added calls to DockingSleep and DockingWakeup to DBLite's sleep
; and wakeup tables so everything will be kept up-to-date.
; <H9> 3/16/92 SWC Modified CPUSpeedMSC to support 16, 20, 25, and 33MHz machines.
; We're only planning to do 25 and 33, but if marketing wants to
; do the slower ones, at least the support's done for free.
; <H8> 3/13/92 SWC Fixed a couple of bugs in CPUSpeedMSC.
; <H7> 3/11/92 SWC Added an entry to the info tables for the address of the power
; cycling register. Added a routine entry for a clamshell switch
; monitoring VBL task. Added an IdleMind routine for DBLite to
; check if the clamshell has been closed.
; <H6> 3/6/92 SWC Added a routine to reset the internal SCC's channel B on wakeup
; since it seems to be getting into a weird state (this may go
; away later once I figure out what's happening, but it will help
; for now).
; <H5> 2/21/92 HJR Added Power cycling to the PrimsRec. Added WakeLvl hysteresis to
; the PrimInfos.
; <H4> 2/7/92 SWC Added default hysteresis and low/dead battery warning levels to
; the primitives info tables.
; <H3> 2/7/92 SWC Added support for determining battery level so we can handle
; different hardware implementations. Made the table offsets in
; PmgrPrimLookup self-relative.
; <H2> 2/4/92 SWC Added support for sleep and wakeup tables. Fixed a bug in
; CPUSpeedMSC. Added assembly conditionals (by decoder) just to be
; thorough. Cleaned up the code here and there. Added padding to
; make the code fixed-size.
; <H1> 2/3/92 HJR first checked in
BLANKS ON
STRING ASIS
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'SoundPrivate.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'PowerPrivEqu.a'
INCLUDE 'PowerMgrDispatchEqu.a'
INCLUDE 'MMUEqu.a'
INCLUDE 'IOPrimitiveEqu.a'
INCLUDE 'DockingEqu.a'
INCLUDE 'ShutDown.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'Video.a'
INCLUDE 'Notification.a'
INCLUDE 'GestaltEqu.a'
INCLUDE 'Processes.a'
INCLUDE 'SlotMgrEqu.a'
INCLUDE 'DepVideoEqu.a'
INCLUDE 'Palettes.a'
INCLUDE 'LayerEqu.a'
INCLUDE 'ENETEqu.a'
PRINT ON
MACHINE MC68030
MC68881
PowerMgrPrimitives PROC EXPORT
IF hasPwrControls THEN
IMPORT AbsoluteBattery ; PowerMgr.a
IMPORT BatWatch ; PowerMgr.a
IMPORT DockingSleep ; DockingMgr.a
IMPORT DockingWakeup ; DockingMgr.a
IMPORT GracefulShutdown ; PowerMgr.a
IMPORT PMGRrecv ; PowerMgr.a
IMPORT PMGRsend ; PowerMgr.a
IMPORT PrivateFeatures ; PowerMgr.a
IMPORT SetSupervisorMode ; PowerMgr.a
EXPORT GetLevel
WITH PmgrRec,PowerDispRec,PmgrPramRec
WITH PmgrPrimitivesRec,PmgrRoutineRec,PrimInfoTbleRec,IdleMindTblRec
WITH pmCommandRec,nmRec,PmgrPramRec,ProcessInfoRec
WITH DecoderInfo,DecoderKinds,ProductInfo,VideoInfo
IF hasJAWS THEN
;••••••••••••••••••••••••••••••••••••••••• JAWS ••••••••••••••••••••••••••••••••••••••••••
EXPORT JawsPmgrPrims
ALIGN 4
DC.L PrimsTypeTable ; flags
DC.L (JawsPmgrPrimsEnd-JawsPmgrPrims) ; size of table
JawsPmgrPrims ; Table of Primitive Tables
DC.L JawsRoutines-JawsPmgrPrims ; offset to table of Jaws routines
DC.L JawsPrimInfo-JawsPmgrPrims ; offset to table decoder-specific constants
DC.L JawsIdleMindTable-JawsPmgrPrims ; offset to table of Idlemind routines
DC.L JawsSleepTable-JawsPmgrPrims ; offset to table of sleep routines
DC.L JawsWakeTable-JawsPmgrPrims ; offset to table of wakeup routines
DC.L 0 ; no PMgrOp exception table
DC.L ModemTable-JawsPmgrPrims ; offset to table modem routines <H31>
DC.L PwrDispatchVects-JawsPmgrPrims ; offset to power dispatch table
DC.L 0 ; no PMgr hook table
DC.L CommsPowerTable-JawsPmgrPrims ; offset to table of comms power routines <K12>
DC.L PMgrOpTbl-JawsPmgrPrims ; offset to routine for PmgrOp
DC.L 0 ; offset to backlight tables
JawsPmgrPrimsEnd
DC.L PrimsTypePtr ; flags
DC.L (JawsRoutinesEnd-JawsRoutines) ; size of table
JawsRoutines ; machine-specific routines
DC.L PowerCycle030-JawsRoutines ; offset to routine for power cycling <H5>
DC.L Restore030-JawsRoutines ; offset to routine for power cycling restore <H5>
DC.L BatWatch-JawsRoutines ; offset to VBL task to check the battery level <H19>
DC.L GetLevel-JawsRoutines ; offset to routine for determining battery level
DC.L LeadScaledBatteryInfo-JawsRoutines ; offset to routine to return scaled battery level<H15>
DC.L 0 ; no enviromental int
DC.L 0 ; no clamshell
DC.L CPUSpeedJaws-JawsRoutines ; offset to routine for determining CPU speed
DC.L SndWatch-JawsRoutines ; offset to VBL task to check for sound usage <H19>
DC.L RedrawScrn-JawsRoutines ; offset to routine for refreshing the screen <H17>
DC.L LeadAbsoluteBatteryVoltage-JawsRoutines; routine to return absolute battery level<H54>
DC.L 0 ; no routine to return info about battery times
DC.L 0 ; dynamic CPU speed change is not supported <H56>
JawsRoutinesEnd
DC.L PrimsTypeInfo ; flags
DC.L (JawsPrimInfoEnd-JawsPrimInfo) ; size of table
JawsPrimInfo ; machine-specific constants:
DC.B $70 ; PRAM base address
DC.B DefHysteresis ; default hysteresis
DC.B PMGRWARNLEVEL-STDOFFSET ; default low battery warning level <H5>
DC.B PMGRCUTOFF-STDOFFSET ; default dead battery warning level <H5>
DC.B PGMRWAKELEVEL-STDOFFSET ; hysteresis setting for pmgr wake level <H5>
DC.B (1-1) ; display shorted battery at second interrupt <H33><H7>
DC.B 0 ; no external video correction needed <H7><H33>
DC.B 0 ; no charger features
DC.L $50FA0000 ; address of power cycling register <H7>
DC.L 0 |\ ; bitmap of public Power Manager features <H52>
(0<<hasWakeupTimer) |\
(1<<hasSharedModemPort) |\
(1<<hasProcessorCycling) |\
(0<<mustProcessorCycle) |\
(1<<hasReducedSpeed) |\
(0<<dynamicSpeedChange) |\
(0<<hasSCSIDiskMode)
DC.L 0 |\ ; bitmap of private Power Manager features <H53>
(0<<hasExtdBattInfo) |\
(0<<hasBatteryID) |\
(0<<canSwitchPower)
DC.W 1 ; number of batteries
DC.B 0 ; Power manager has a parallel interface
DC.B 0 ; padding for now
DC.L 0 ; no extended charge time
DC.B 0 ; value for power cycling register <K22>
DC.B 0 ; value for sleep register <K22>
DC.B 0 ; padding for now
DC.B 0 ; padding for now
JawsPrimInfoEnd
DC.L PrimsTypePtr ; flags
DC.L (JawsIdleMindTableEnd-JawsIdleMindTable); size of table
JawsIdleMindTable ; machine specific IdleMind Routines
DC.L CheckCountDownTimer-JawsIdleMindTable ; offset to count down timer
DC.L RunIdleRoutinesProc-JawsIdleMindTable ; offset to run idle procs
DC.L ChkSleepTimeOut-JawsIdleMindTable ; offset to sleep time out
DC.L ChkIdle-JawsIdleMindTable ; offset to check idle
DC.L CalcProgressive-JawsIdleMindTable ; offset to calc progressive
DC.L GoPowerCycle-JawsIdleMindTable ; offset to go power cycle
JawsIdleMindTableEnd
DC.L PrimsTypePtr ; flags
DC.L (JawsSleepTableEnd-JawsSleepTable) ; size of table
JawsSleepTable ; list of routines to execute when going to sleep:
DC.L SleepHD-JawsSleepTable ; sleep the hard drive if currently running <K22>
DC.L SaveVIA1-JawsSleepTable ; save VIA1 registers
DC.L SaveASCBatman-JawsSleepTable ; save ASC/Batman registers
DC.L SaveFPU-JawsSleepTable ; save FPU registers
DC.L SaveVIA2-JawsSleepTable ; save VIA2 registers
DC.L SendSleep-JawsSleepTable ; send a sleep command
DC.L SaveSlp030-JawsSleepTable ; save MMU registers
DC.L SaveSleepInfo-JawsSleepTable ; save sleep info in video RAM
DC.L 0 ; (end of table)
JawsSleepTableEnd
DC.L PrimsTypePtr ; flags
DC.L (JawsWakeTableEnd-JawsWakeTable) ; size of table
JawsWakeTable ; list of routines to execute when waking up:
DC.L RestoreSlp030-JawsWakeTable ; restore MMU, SPs, cache registers
DC.L RestoreVIA2-JawsWakeTable ; restore VIA2 registers
DC.L RestoreFPU-JawsWakeTable ; restore FPU registers
DC.L RestoreASCBatman-JawsWakeTable ; restore ASC and Batman registers
DC.L RestoreVIA1-JawsWakeTable ; restore VIA1 registers
DC.L WakeClrInts-JawsWakeTable ; clear any pending PmgrInterrupts
DC.L WakeSoundSetJaws-JawsWakeTable ; set state for sound out of sleep
DC.L 0 ; (end of table)
JawsWakeTableEnd
ALIGN 4
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CPUSpeedJaws
;
; Inputs: none
;
; Outputs: D0 - [maximum CPU speed][current CPU speed]
;
; Trashes: A0
;
; Function: returns the maximum and current (econo-mode or full) CPU speeds for
; JAWS-based machines
;————————————————————————————————————————————————————————————————————————————————————————
CPUSpeedJaws
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 JAWS base address,
ADDA.L #JAWSGetCPUClock,A0 ; and finally to the CPU clock register
BTST #0,(A0) ; are we a 25MHz or 16MHz machine?
ADDA.L #JAWSEconoMode-JAWSGetCPUClock,A0 ; (point to the econo-mode register)
BEQ.S @16MHz ; -> 16MHz
MOVE.L #(CPUSpeed25MHz<<16)|\ ; assume we're running full-speed at 25MHz
(CPUSpeed25MHz<<0),D0
BTST #1,(A0) ; are we in econo-mode?
BEQ.S @NoEcono25 ; -> nope, we're done
MOVE.W #CPUSpeed16MHz,D0 ; yes, we're currently running at 16MHz
@NoEcono25 RTS
@16MHz MOVE.L #(CPUSpeed16MHz<<16)|\ ; assume we're running full-speed at 16MHz
(CPUSpeed16MHz<<0),D0
BTST #1,(A0) ; are we in econo-mode?
BEQ.S @NoEcono16 ; -> nope, we're done
MOVE.W #CPUSpeed8MHz,D0 ; yes, we're currently running at 8MHz
@NoEcono16 RTS
ENDIF
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine for setting sound (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
WakeSoundSetNiagra
WakeSoundSetJaws
MOVEM.L A0-A1,-(SP) ; save special registers
SUBQ.W #4,SP ; Create stack frame
MOVE.L SP,A0
MOVE.B #sndClrLtch,(A0) ; Clear the Sound latch
MOVEQ #1,D1 ; One long to send
MOVE.W #SoundSet,D0 ; PMGR command, Set Sound Control
MOVE.L A2,-(SP)
BigJSR PMGRsend,A2 ; have the PMGR clear the sound latch
MOVE.L (SP)+,A2
ADDQ.W #4,SP ; Remove stack frame
With ExpandmemRec,SoundIOHeader
MOVEA.L ([Expandmem],\
emSndPrimitives),A0 ; Get pointer to Expandmem
MOVE.B DFAClast(A0),D0 ; get last byte sent to DFAC
jsrTBL sndDFACSend,A0 ; send byte to DFAC
Endwith
MOVEM.L (SP)+,A0-A1 ; restore special registers
JMP (A1) ; go home
IF hasMSC THEN
;••••••••••••••••••••••••••••••••••••••••• MBT •••••••••••••••••••••••••••••••••••••••••••
EXPORT MBTPmgrPrims
ALIGN 4
DC.L PrimsTypeTable ; flags
DC.L (MBTPmgrPrimsEnd-MBTPmgrPrims) ; size of table
MBTPmgrPrims ; Table of Primitives tables
DC.L MBTRoutines-MBTPmgrPrims ; offset to table of MSC routines
DC.L MBTPrimInfo-MBTPmgrPrims ; offset to decoder-specific constants
DC.L MBTIdleMindTable-MBTPmgrPrims ; offset to table of Idlemind routines <H7>
DC.L MBTSleepTable-MBTPmgrPrims ; offset to table of sleep routines
DC.L MBTWakeTable-MBTPmgrPrims ; offset to table of wakeup routines
DC.L MBTModemTable-MBTPmgrPrims ; offset to table of modem routines <H31>
DC.L MBTPMgrOpExceptions-MBTPmgrPrims ; offset to PMgrOp exception table
DC.L PwrDispatchVects-MBTPmgrPrims ; offset to table of PwrDispatchVects
DC.L PMgrHookVects-MBTPmgrPrims ; offset to table of PmgrMgr Hooks
DC.L 0 ; no comms power routines <K12>
DC.L PMgrOpTbl-MBTPmgrPrims ; offset to routine for PmgrOp
DC.L 0 ; offset to backlight tables
MBTPmgrPrimsEnd
DC.L PrimsTypePtr ; flags
DC.L (MBTRoutinesEnd-MBTRoutines) ; size of table
MBTRoutines ; machine-specific routines
DC.L PowerCycle040-MBTRoutines ; offset to routine for power cycling <H5>
DC.L Restore040-MBTRoutines ; offset to routine for power cycling restore <H5>
DC.L BatWatch-MBTRoutines ; offset to VBL task to check the battery level <H19>
DC.L GetExtLevel-MBTRoutines ; offset to routine for determining battery level
DC.L MultiScaledBatteryInfo-MBTRoutines ; offset to routine to return scaled battery level <H15>
DC.L 0 ; no environment interrupts
DC.L ClamshellVBL-MBTRoutines ; offset to VBL task to check for clamshell closed <H7>
DC.L CPUSpeedMSC-MBTRoutines ; offset to routine for determining CPU speed
DC.L SndWatchMSC-MBTRoutines ; offset to VBL task to check for sound usage <H19>
DC.L RedrawScrn-MBTRoutines ; offset to routine for refreshing the screen <H18>
DC.L PGEAbsoluteBatteryVoltage-MBTRoutines ; routine to return absolute battery level <H54>
DC.L 0 ; no routine to return info about battery times
DC.L 0 ; dynamic CPU speed change is not supported
MBTRoutinesEnd
DC.L PrimsTypeInfo ; flags
DC.L (MBTPrimInfoEnd-MBTPrimInfo) ; size of table
MBTPrimInfo ; machine-specific constants:
DC.B $46 ; PRAM base address
DC.B DefHysteresis ; default hysteresis
DC.B 0 ; default low battery warning level (none) <H12>
DC.B 0 ; default dead battery warning level (none) <H12>
DC.B 0 ; hysteresis setting for wake level (none) <H12>
DC.B 0 ; shorted battery at first interrupt (none) <H33> <H7>
DC.B 0 ; no external video correction needed <H7>
DC.B 0 |\ ; bitmap of charger attributes
(1<<hasSleepLED) |\
(1<<hasForcedDischarge) |\
(0<<hasDBCharger) |\
(1<<hasEscherCharger)
DC.L $50FA0000 ; address of power cycling register <H7>
DC.L 0 |\ ; bitmap of Power Manager features <H52>
(1<<hasWakeupTimer) |\
(0<<hasSharedModemPort) |\
(1<<hasProcessorCycling) |\
(0<<mustProcessorCycle) |\
(0<<hasReducedSpeed) |\
(0<<dynamicSpeedChange) |\
(1<<hasSCSIDiskMode)
DC.L 0 |\ ; bitmap of private Power Manager features <H53>
(1<<hasExtdBattInfo) |\
(1<<hasBatteryID) |\
(0<<canSwitchPower)
DC.W 1 ; number of batteries
DC.B 2 ; Power Manager Serial Interface <H7>
DC.B 0 ; padding for now
DC.L 0 ; no extended charging
DC.B $5A ; value for power cycling register <K22>
DC.B 0 ; value for sleep register <K22>
DC.B 0 ; padding for now
DC.B 0 ; padding for now
MBTPrimInfoEnd
DC.L PrimsTypePtr ; flags
DC.L (MBTIdleMindTableEnd-MBTIdleMindTable); size of table
MBTIdleMindTable ; machine specific IdleMind Routines
DC.L CheckCountDownTimer-MBTIdleMindTable; offset to count down timer
DC.L CheckClamshell-MBTIdleMindTable ; offset to clam shell <H20>
DC.L ChkSleepTimeOut-MBTIdleMindTable ; offset to sleep time out
DC.L ChkIdle-MBTIdleMindTable ; offset to check idle
DC.L CalcProgressive-MBTIdleMindTable ; offset to calc progressive
DC.L GoPowerCycle-MBTIdleMindTable ; offset to go power cycle
MBTIdleMindTableEnd
DC.L PrimsTypePtr ; flags
DC.L (MBTSleepTableEnd-MBTSleepTable) ; size of table
MBTSleepTable ; list of routines to execute when going to sleep:
DC.L SleepHD-MBTSleepTable ; sleep the hard drive if currently running <K22>
DC.L DockingSleep-MBTSleepTable ; save state of currently connected bar <H10>
DC.L SaveVIA1-MBTSleepTable ; save VIA1 registers
DC.L SaveASCBatman-MBTSleepTable ; save ASC/Batman registers
DC.L SaveFPU-MBTSleepTable ; save FPU registers
DC.L SaveLCD-MBTSleepTable ; save GSC (built-in LCD video) registers
DC.L SaveMSC-MBTSleepTable ; save MSC registers
DC.L SendSleepLP-MBTSleepTable ; send a sleep command <H42>
DC.L SaveSlp040-MBTSleepTable ; save MMU registers
DC.L SaveSleepInfo-MBTSleepTable ; save sleep info in Power Manager globals
DC.L MSCKillPower-MBTSleepTable ; have MSC pull the plug as well
DC.L 0 ; (end of table)
MBTSleepTableEnd
DC.L PrimsTypePtr ; flags
DC.L (MBTWakeTableEnd-MBTWakeTable) ; size of table
MBTWakeTable ; list of routines to execute when waking up:
DC.L RestoreSlp040-MBTWakeTable ; restore MMU, SPs, cache registers
DC.L RestoreMSC-MBTWakeTable ; restore volatile MSC registers
DC.L RestoreLCD-MBTWakeTable ; restore GSC (built-in LCD video) registers
DC.L RestoreFPU-MBTWakeTable ; restore FPU registers
DC.L RestoreASCBatman-MBTWakeTable ; restore ASC and Batman registers
DC.L RestoreVIA1-MBTWakeTable ; restore VIA1 registers
DC.L MSCInitSCC-MBTWakeTable ; reset channel B on internal SCC <H6>
DC.L DockingWakeup-MBTWakeTable ; restore state of currently connected bar <H10>
DC.L WakeClrInts-MBTWakeTable ; clear any pending PmgrInterrupts
DC.L WakeSoundSet-MBTWakeTable ; set state for sound out of sleep
DC.L 0 ; (end of table)
MBTWakeTableEnd
DC.L PrimsTypePMgrEx ; flags
DC.L (MBTPMgrOpExceptionsEnd-MBTPMgrOpExceptions) ; size of table
MBTPMgrOpExceptions ; PMgrOp exceptions:
DC.B $FF,powerCntl ; $10 - power control
DC.L MSCPowerControl-*
DC.B $FF,powerRead ; $18 - power status
DC.L MSCPowerStatus-*
DC.B $FF,$1F ; $1F - fake power status (for MSC/PG&E)
DC.L MSCFakePowerStatus-*
DC.B $FE,batteryRead ; $68, $69 - read battery status
DC.L MSCReadBattery-*
DC.B $FF,soundSet ; $90 - clear sound latch, turn sound power on/off
DC.L MSCSetSound-*
DC.B $FF,soundRead ; $98 - return sound latch, sound power status
DC.L MSCReadSound-*
DC.W 0 ; (end of table)
MBTPMgrOpExceptionsEnd
DC.L PrimsTypePtr ; flags <K10>
DC.L (MBTModemTableEnd-MBTModemTable) ; size of table
MBTModemTable
DC.L 0 ; offset to routine to turn on modem
DC.L 0 ; offset to routine to turn off modem
DC.L DBLiteModemType-MBTModemTable ; offset to routine to get modem type
MBTModemTableEnd
ALIGN 4
;••••••••••••••••••••••••••••••••••••••••• MSC2 •••••••••••••••••••••••••••••••••••••••••••
EXPORT MSC2PmgrPrims
ALIGN 4
DC.L PrimsTypeTable ; flags
DC.L (MSC2PmgrPrimsEnd-MSC2PmgrPrims) ; size of table
MSC2PmgrPrims ; Table of Primitives tables
DC.L MSC2Routines-MSC2PmgrPrims ; offset to table of MSC routines
DC.L MSC2PrimInfo-MSC2PmgrPrims ; offset to decoder-specific constants
DC.L MSC2IdleMindTable-MSC2PmgrPrims ; offset to table of Idlemind routines <H7>
DC.L MSC2SleepTable-MSC2PmgrPrims ; offset to table of sleep routines
DC.L MSC2WakeTable-MSC2PmgrPrims ; offset to table of wakeup routines
DC.L MSC2ModemTable-MSC2PmgrPrims ; offset to table of modem routines <H31>
DC.L MSC2PMgrOpExceptions-MSC2PmgrPrims ; offset to PMgrOp exception table
DC.L PwrDispatchVects-MSC2PmgrPrims ; offset to table of PwrDispatchVects
DC.L PMgrHookVects-MSC2PmgrPrims ; offset to table of PmgrMgr Hooks
DC.L 0 ; no comms power routines <K12>
DC.L PMgrOpTbl-MSC2PmgrPrims ; offset to routine for PmgrOp
DC.L 0 ; offset to backlight tables
MSC2PmgrPrimsEnd
DC.L PrimsTypePtr ; flags
DC.L (MSC2RoutinesEnd-MSC2Routines) ; size of table
MSC2Routines ; machine-specific routines
DC.L PowerCycle040-MSC2Routines ; offset to routine for power cycling <H5>
DC.L Restore040-MSC2Routines ; offset to routine for power cycling restore <H5>
DC.L BatWatch-MSC2Routines ; offset to VBL task to check the battery level <H19>
DC.L GetExtLevel-MSC2Routines ; offset to routine for determining battery level
DC.L MultiScaledBatteryInfo-MSC2Routines ; offset to routine to return scaled battery level <H15>
DC.L 0 ; no environment interrupts
DC.L ClamshellVBL-MSC2Routines ; offset to VBL task to check for clamshell closed <H7>
DC.L CPUSpeedMSC-MSC2Routines ; offset to routine for determining CPU speed
DC.L SndWatchMSC-MSC2Routines ; offset to VBL task to check for sound usage <H19>
DC.L RedrawScrn-MSC2Routines ; offset to routine for refreshing the screen <H18>
DC.L PGEAbsoluteBatteryVoltage-MSC2Routines ; routine to return absolute battery level <H54>
DC.L 0 ; no routine to return info about battery times
DC.L 0 ; dynamic CPU speed change is not supported
MSC2RoutinesEnd
DC.L PrimsTypeInfo ; flags
DC.L (MSC2PrimInfoEnd-MSC2PrimInfo) ; size of table
MSC2PrimInfo ; machine-specific constants:
DC.B $46 ; PRAM base address
DC.B DefHysteresis ; default hysteresis
DC.B 0 ; default low battery warning level (none) <H12>
DC.B 0 ; default dead battery warning level (none) <H12>
DC.B 0 ; hysteresis setting for wake level (none) <H12>
DC.B 0 ; shorted battery at first interrupt (none) <H33> <H7>
DC.B 0 ; no external video correction needed <H7>
DC.B 0 |\ ; bitmap of charger attributes
(1<<hasSleepLED) |\
(1<<hasForcedDischarge) |\
(0<<hasDBCharger) |\
(1<<hasEscherCharger)
DC.L $50FA0000 ; address of power cycling register <H7>
DC.L 0 |\ ; bitmap of Power Manager features <H52>
(1<<hasWakeupTimer) |\
(0<<hasSharedModemPort) |\
(1<<hasProcessorCycling) |\
(0<<mustProcessorCycle) |\
(0<<hasReducedSpeed) |\
(0<<dynamicSpeedChange) |\
(1<<hasSCSIDiskMode)
DC.L 0 |\ ; bitmap of private Power Manager features <H53>
(1<<hasExtdBattInfo) |\
(1<<hasBatteryID) |\
(0<<canSwitchPower)
DC.W 1 ; number of batteries
DC.B 2 ; Power Manager Serial Interface <H7>
DC.B 0 ; padding for now
DC.L 0 ; no extended charging
DC.B $5A ; value for power cycling register <K22>
DC.B 0 ; value for sleep register <K22>
DC.B 0 ; padding for now
DC.B 0 ; padding for now
MSC2PrimInfoEnd
DC.L PrimsTypePtr ; flags
DC.L (MSC2IdleMindTableEnd-MSC2IdleMindTable); size of table
MSC2IdleMindTable ; machine specific IdleMind Routines
DC.L CheckCountDownTimer-MSC2IdleMindTable; offset to count down timer
DC.L CheckClamshell-MSC2IdleMindTable ; offset to clam shell <H20>
DC.L ChkSleepTimeOut-MSC2IdleMindTable ; offset to sleep time out
DC.L ChkIdle-MSC2IdleMindTable ; offset to check idle
DC.L CalcProgressive-MSC2IdleMindTable ; offset to calc progressive
DC.L GoPowerCycle-MSC2IdleMindTable ; offset to go power cycle
MSC2IdleMindTableEnd
DC.L PrimsTypePtr ; flags
DC.L (MSC2SleepTableEnd-MSC2SleepTable) ; size of table
MSC2SleepTable ; list of routines to execute when going to sleep:
DC.L SleepHD-MSC2SleepTable ; sleep the hard drive if currently running <K22>
DC.L DockingSleep-MSC2SleepTable ; save state of currently connected bar <H10>
DC.L SaveVIA1-MSC2SleepTable ; save VIA1 registers
DC.L SaveASCBatman-MSC2SleepTable ; save ASC/Batman registers
DC.L SaveFPU-MSC2SleepTable ; save FPU registers
DC.L SaveLCD-MSC2SleepTable ; save GSC (built-in LCD video) registers
DC.L SaveMSC-MSC2SleepTable ; save MSC registers
DC.L SendSleepLP-MSC2SleepTable ; send a sleep command <H42>
DC.L SaveSlp040-MSC2SleepTable ; save MMU registers
DC.L SaveSleepInfo-MSC2SleepTable ; save sleep info in Power Manager globals
DC.L MSCKillPower-MSC2SleepTable ; have MSC pull the plug as well
DC.L 0 ; (end of table)
MSC2SleepTableEnd
DC.L PrimsTypePtr ; flags
DC.L (MSC2WakeTableEnd-MSC2WakeTable) ; size of table
MSC2WakeTable ; list of routines to execute when waking up:
DC.L RestoreSlp040-MSC2WakeTable ; restore MMU, SPs, cache registers
DC.L RestoreMSC-MSC2WakeTable ; restore volatile MSC registers
DC.L RestoreLCD-MSC2WakeTable ; restore GSC (built-in LCD video) registers
DC.L RestoreFPU-MSC2WakeTable ; restore FPU registers
DC.L RestoreASCBatman-MSC2WakeTable ; restore ASC and Batman registers
DC.L RestoreVIA1-MSC2WakeTable ; restore VIA1 registers
DC.L MSCInitSCC-MSC2WakeTable ; reset channel B on internal SCC <H6>
DC.L DockingWakeup-MSC2WakeTable ; restore state of currently connected bar <H10>
DC.L WakeClrInts-MSC2WakeTable ; clear any pending PmgrInterrupts
DC.L WakeSoundSet-MSC2WakeTable ; set state for sound out of sleep
DC.L 0 ; (end of table)
MSC2WakeTableEnd
DC.L PrimsTypePMgrEx ; flags
DC.L (MSC2PMgrOpExceptionsEnd-MSC2PMgrOpExceptions) ; size of table
MSC2PMgrOpExceptions ; PMgrOp exceptions:
DC.B $FF,powerCntl ; $10 - power control
DC.L MSCPowerControl-*
DC.B $FF,powerRead ; $18 - power status
DC.L MSCPowerStatus-*
DC.B $FF,$1F ; $1F - fake power status (for MSC/PG&E)
DC.L MSCFakePowerStatus-*
DC.B $FE,batteryRead ; $68, $69 - read battery status
DC.L MSCReadBattery-*
DC.B $FF,soundSet ; $90 - clear sound latch, turn sound power on/off
DC.L MSCSetSound-*
DC.B $FF,soundRead ; $98 - return sound latch, sound power status
DC.L MSCReadSound-*
DC.W 0 ; (end of table)
MSC2PMgrOpExceptionsEnd
DC.L PrimsTypePtr ; flags <K10>
DC.L (MSC2ModemTableEnd-MSC2ModemTable) ; size of table
MSC2ModemTable
DC.L 0 ; offset to routine to turn on modem
DC.L 0 ; offset to routine to turn off modem
DC.L DBLiteModemType-MSC2ModemTable ; offset to routine to get modem type
MSC2ModemTableEnd
ALIGN 4
;••••••••••••••••••••••••••••••••••••••••• MSC •••••••••••••••••••••••••••••••••••••••••••
EXPORT MSCPmgrPrims
ALIGN 4
DC.L PrimsTypeTable ; flags
DC.L (MSCPmgrPrimsEnd-MSCPmgrPrims) ; size of table
MSCPmgrPrims ; Table of Primitives tables
DC.L MSCRoutines-MSCPmgrPrims ; offset to table of MSC routines
DC.L MSCPrimInfo-MSCPmgrPrims ; offset to decoder-specific constants
DC.L MSCIdleMindTable-MSCPmgrPrims ; offset to table of Idlemind routines <H7>
DC.L MSCSleepTable-MSCPmgrPrims ; offset to table of sleep routines
DC.L MSCWakeTable-MSCPmgrPrims ; offset to table of wakeup routines
DC.L MSCModemTable-MSCPmgrPrims ; offset to table of modem routines <H31>
DC.L MSCPMgrOpExceptions-MSCPmgrPrims ; offset to PMgrOp exception table
DC.L PwrDispatchVects-MSCPmgrPrims ; offset to table of PwrDispatchVects
DC.L PMgrHookVects-MSCPmgrPrims ; offset to table of PmgrMgr Hooks
DC.L 0 ; no comms power routines <K12>
DC.L PMgrOpTbl-MSCPmgrPrims ; offset to routine for PmgrOp
DC.L 0 ; offset to backlight tables
MSCPmgrPrimsEnd
DC.L PrimsTypePtr ; flags
DC.L (MSCRoutinesEnd-MSCRoutines) ; size of table
MSCRoutines ; machine-specific routines
DC.L PowerCycle030-MSCRoutines ; offset to routine for power cycling <H5>
DC.L Restore030-MSCRoutines ; offset to routine for power cycling restore <H5>
DC.L BatWatch-MSCRoutines ; offset to VBL task to check the battery level <H19>
DC.L GetExtLevel-MSCRoutines ; offset to routine for determining battery level
DC.L MultiScaledBatteryInfo-MSCRoutines ; offset to routine to return scaled battery level <H15>
DC.L 0 ; no environment interrupts
DC.L ClamshellVBL-MSCRoutines ; offset to VBL task to check for clamshell closed <H7>
DC.L CPUSpeedMSC-MSCRoutines ; offset to routine for determining CPU speed
DC.L SndWatchMSC-MSCRoutines ; offset to VBL task to check for sound usage <H19>
DC.L RedrawScrn-MSCRoutines ; offset to routine for refreshing the screen <H18>
DC.L PGEAbsoluteBatteryVoltage-MSCPmgrPrims ; routine to return absolute battery level <H54>
DC.L 0 ; no routine to return info about battery times
DC.L ChangeCPUSpeedMSC-MSCPmgrPrims ; routine to do a dynamic CPU speed change <H56>
MSCRoutinesEnd
DC.L PrimsTypeInfo ; flags
DC.L (MSCPrimInfoEnd-MSCPrimInfo) ; size of table
MSCPrimInfo ; machine-specific constants:
DC.B $46 ; PRAM base address
DC.B DefHysteresis ; default hysteresis
DC.B 0 ; default low battery warning level (none) <H12>
DC.B 0 ; default dead battery warning level (none) <H12>
DC.B 0 ; hysteresis setting for wake level (none) <H12>
DC.B 0 ; shorted battery at first interrupt (none) <H33> <H7>
DC.B 0 ; no external video correction needed <H7>
DC.B 0 ; no charger features
DC.L $50FA0000 ; address of power cycling register <H7>
DC.L 0 |\ ; bitmap of Power Manager features <H52>
(1<<hasWakeupTimer) |\
(0<<hasSharedModemPort) |\
(1<<hasProcessorCycling) |\
(0<<mustProcessorCycle) |\
(1<<hasReducedSpeed) |\
(1<<dynamicSpeedChange) |\
(1<<hasSCSIDiskMode)
DC.L 0 |\ ; bitmap of private Power Manager features <H53>
(1<<hasExtdBattInfo) |\
(1<<hasBatteryID) |\
(0<<canSwitchPower)
DC.W 1 ; number of batteries
DC.B 2 ; Power Manager Serial Interface <H7>
DC.B 0 ; padding for now
DC.L 0 ; no extended charging
DC.B $5A ; value for power cycling register <K22>
DC.B 0 ; value for sleep register <K22>
DC.B 0 ; padding for now
DC.B 0 ; padding for now
MSCPrimInfoEnd
DC.L PrimsTypePtr ; flags
DC.L (MSCIdleMindTableEnd-MSCIdleMindTable); size of table
MSCIdleMindTable ; machine specific IdleMind Routines
DC.L CheckCountDownTimer-MSCIdleMindTable; offset to count down timer
DC.L CheckClamshell-MSCIdleMindTable ; offset to clam shell <H20>
DC.L ChkSleepTimeOut-MSCIdleMindTable ; offset to sleep time out
DC.L ChkIdle-MSCIdleMindTable ; offset to check idle
DC.L CalcProgressive-MSCIdleMindTable ; offset to calc progressive
DC.L GoPowerCycle-MSCIdleMindTable ; offset to go power cycle
MSCIdleMindTableEnd
DC.L PrimsTypePtr ; flags
DC.L (MSCSleepTableEnd-MSCSleepTable) ; size of table
MSCSleepTable ; list of routines to execute when going to sleep:
DC.L SleepHD-MSCSleepTable ; sleep the hard drive if currently running
DC.L DockingSleep-MSCSleepTable ; save state of currently connected bar <H10>
DC.L SaveVIA1-MSCSleepTable ; save VIA1 registers
DC.L SaveASCBatman-MSCSleepTable ; save ASC/Batman registers
DC.L SaveFPU-MSCSleepTable ; save FPU registers
DC.L SaveLCD-MSCSleepTable ; save GSC (built-in LCD video) registers
DC.L SaveMSC-MSCSleepTable ; save MSC registers
DC.L SendSleepLP-MSCSleepTable ; send a sleep command <H42>
DC.L SaveSlp030-MSCSleepTable ; save MMU registers
DC.L SaveSleepInfo-MSCSleepTable ; save sleep info in Power Manager globals
DC.L MSCKillPower-MSCSleepTable ; have MSC pull the plug as well
DC.L 0 ; (end of table)
MSCSleepTableEnd
DC.L PrimsTypePtr ; flags
DC.L (MSCWakeTableEnd-MSCWakeTable) ; size of table
MSCWakeTable ; list of routines to execute when waking up:
DC.L RestoreSlp030-MSCWakeTable ; restore MMU, SPs, cache registers
DC.L RestoreMSC-MSCWakeTable ; restore volatile MSC registers
DC.L RestoreLCD-MSCWakeTable ; restore GSC (built-in LCD video) registers
DC.L RestoreFPU-MSCWakeTable ; restore FPU registers
DC.L RestoreASCBatman-MSCWakeTable ; restore ASC and Batman registers
DC.L RestoreVIA1-MSCWakeTable ; restore VIA1 registers
DC.L MSCInitSCC-MSCWakeTable ; reset channel B on internal SCC <H6>
DC.L DockingWakeup-MSCWakeTable ; restore state of currently connected bar <H10>
DC.L WakeClrInts-MSCWakeTable ; clear any pending PmgrInterrupts
DC.L WakeSoundSet-MSCWakeTable ; set state for sound out of sleep
DC.L 0 ; (end of table)
MSCWakeTableEnd
DC.L PrimsTypePMgrEx ; flags
DC.L (MSCPMgrOpExceptionsEnd-MSCPMgrOpExceptions) ; size of table
MSCPMgrOpExceptions ; PMgrOp exceptions:
DC.B $FF,powerCntl ; $10 - power control
DC.L MSCPowerControl-*
DC.B $FF,powerRead ; $18 - power status
DC.L MSCPowerStatus-*
DC.B $FF,$1F ; $1F - fake power status (for MSC/PG&E)
DC.L MSCFakePowerStatus-*
DC.B $FE,batteryRead ; $68, $69 - read battery status
DC.L MSCReadBattery-*
DC.B $FF,soundSet ; $90 - clear sound latch, turn sound power on/off
DC.L MSCSetSound-*
DC.B $FF,soundRead ; $98 - return sound latch, sound power status
DC.L MSCReadSound-*
DC.W 0 ; (end of table)
MSCPMgrOpExceptionsEnd
DC.L PrimsTypePtr ; flags <K10>
DC.L (MSCModemTableEnd-MSCModemTable) ; size of table
MSCModemTable
DC.L 0 ; offset to routine to turn on modem
DC.L 0 ; offset to routine to turn off modem
DC.L DBLiteModemType-MSCModemTable ; offset to routine to get modem type
MSCModemTableEnd
ALIGN 4
;_______________________________________________________________________________________
;
; Routine: MSCReadBattery
;
; Inputs: A0 -- pointer to caller's parameter block
;
; Outputs: D0 -- result code
; CCR-- always BEQ
;
; Trashes: D1,A0-A1
;
; Function: Emulates the read battery status ($68) and instantaneous battery status ($69)
; calls since they're not supported by PG&E. The contents of the receive buffer
; are mapped as follows:
;
; extended status ($6B) read status ($68 or $69)
; +0 flags (bits) flags (bits)
; 7: chargeable battery 7: 0
; 6: "energy used" count valid 6: 0
; 5: 0 5: charger state change
; 4: battery termperature valid 4: low battery
; 3: dead battery 3: dead battery (always 0)
; 2: battery connected 2: hi-charge counter overflow
; 1: hi-charge enabled 1: hi-charge enabled
; 0: charger installed 0: charger installed
; +1 voltage (H) 0-511 -> 7-21 volts power
; +2 voltage (L) ambient temperature
; +3 ambient temperature (°C) -
; +4 battery temperature (°C) -
; +5 power usage rate (* 66.9 = mW) -
; +6 energy used (H) -
; +7 energy used (L) -
;_______________________________________________________________________________________
MSCReadBattery
MOVEA.L A0,A1 ; save the parameter block pointer
SUBQ.W #8,SP ; make space for a buffer
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0 (no bytes sent)
MOVE.W #readExtBatt,-(SP) ; pmCommand = read extended battery status
MOVE.L SP,A0
_PMgrOp ; get extended battery status
LEA pmRBuffer+4(SP),SP ; (get rid of the parameter block)
BNE.S @CantRead ; -> error
MOVEA.L SP,A0 ; point to our reply buffer
MOVE.W #3,pmLength(A1) ; stuff the reply count
MOVEA.L pmRBuffer(A1),A1 ; point to the reply buffer
MOVEQ #%00001011,D1 ; mask off the relevant flag bits
AND.B (A0),D1
MOVE.B D1,(A1)+ ; and stuff them into the buffer
MOVEQ #0,D1 ; assume no battery
BTST #2,(A0)+ ; is there one?
BEQ.S @NoBattery ; -> no, return zero volts
MOVE.W (A0),D1 ; get the battery voltage
LSR.W #1,D1 ; for now, just scale it into 0-255
@NoBattery MOVE.B D1,(A1)+
ADDQ.W #2,A0 ; (skip over voltage)
MOVE.B (A0)+,(A1)+ ; •••for now, just copy the temperature across
@CantRead ADDQ.W #8,SP ; get rid of the buffer
MOVEQ #0,D1 ; set CCR for BEQ
RTS
;_______________________________________________________________________________________
;
; Routine: MSCPowerControl
;
; Inputs: A0 -- pointer to caller's parameter block
;
; Outputs: D0 -- result code
; CCR-- BEQ if the call was emulated, else BNE
;
; Trashes: D1-D2, A1
;
; Function: Emulates all or part of the powerCntl call ($10) for systems where not all
; power planes are controlled by the PMGR. The send buffer will contain a
; byte with the following bits used:
;
; bit 0: 1=IWM power
; 1: 1=SCC power
; 2: 1=hard disk power
; 3: 1=internal modem power
; 4: 1=serial output driver power
; 5: 1=sound power
; 6: 1=minus 5 volt power
; 7: 1=turn on, 0=turn off devices corresponding to 1's in bits 0-6
;_______________________________________________________________________________________
Unimplement EQU $A89F ; _Unimplemented trap
MSCPowerControl
MOVEA.L pmSBuffer(A0),A1 ; point to the transmit buffer
MOVEQ #0,D1
MOVE.B (A1),D1 ; get the data byte
MOVEM.L D1/A0,-(SP)
MOVE.W #Unimplement,D0 ; does the _DockingDispatch trap exist?
_GetTrapAddress ,NEWTOOL
MOVEA.L A0,A1
MOVE.W @DockTrap,D0
_GetTrapAddress ,NEWTOOL
CMPA.L A0,A1
BEQ.S @NoDocking ; -> no, just turn internal power planes on/off
SUBQ.W #4,SP ; result
PEA dockPowerControl ; docking selector = power control
MOVE.L D1,-(SP) ; params = which power planes to affect
@DockTrap _DockingDispatch ; call the handler
ADDQ.W #4,SP ; toss the result
@NoDocking MOVEM.L (SP)+,D1/A0
MOVEA.L VIA2,A1 ; point to the base of the MSC
MOVEQ #(1<<pSCC) | (1<<pSerDrvr),D0 ; mask off the SCC power and serial drivers bits
AND.B D1,D0 ; are either of them set?
BEQ.S @NoSCC ; -> nope
EOR.B D0,D1 ; turn them both off
TST.B D1 ; turn power on or off?
BMI.S @TurnOnSCC
BCLR #MSCSCCClk,MSCClkCntl(A1) ; turn off SCC PCLK, RTXC
BRA.S @NoSCC
@TurnOnSCC BSET #MSCSCCClk,MSCClkCntl(A1) ; turn on SCC PCLK, RTXC
@NoSCC BTST #pHD,D1 ; is hard disk power being turned on/off?
BEQ.S @NoHD ; -> no
TST.B D1 ; turn power on or off?
BMI.S @TurnOnSCSI
BCLR #MSCSCSIReset,MSCClkCntl(A1) ; drive SCSI chip reset low to stop clocks
BRA.S @NoHD
@TurnOnSCSI BSET #MSCSCSIReset,MSCClkCntl(A1) ; drive SCSI chip reset high to start it up
@NoHD BCLR #pASC,D1 ; is sound power being turned on/off?
BEQ.S @NoSound ; -> nope
TST.B D1 ; turn power on or off?
BMI.S @TurnOnSnd
BCLR #MSCSndPower,MSCSndCntl(A1) ; turn off sound power
BRA.S @NoSound
@TurnOnSnd BSET #MSCSndPower,MSCSndCntl(A1) ; turn off sound power
@NoSound BCLR #pIWM,D1 ; clear the SWIM power bit
@NoSWIM MOVEQ #$7F,D0 ; return BNE if any bits are still set
AND.B D1,D0 ; so we can pass it on to the PMGR
BNE.S @MorePower ; -> more for the PMGR to do
CLR.W pmLength(A0) ; fix the returned length since we're done
@MorePower RTS
;_______________________________________________________________________________________
;
; Routine: MSCPowerStatus
;
; Inputs: A0 -- pointer to caller's parameter block
;
; Outputs: D0 -- result code
; CCR-- BEQ if the call was emulated, else BNE
;
; Trashes: D1-D2, A0-A1
;
; Function: Emulates all or part of the powerRead call ($18) for systems where not all
; power planes are controlled by the PMGR. On exit, the receive buffer will
; contain a byte with the following bits used:
;
; bit 0: 1=IWM power
; 1: 1=SCC power
; 2: 1=hard disk power
; 3: 1=internal modem power
; 4: 1=serial output driver power
; 5: 1=sound power
; 6: 1=minus 5 volt power
; 7: 1=turn on, 0=turn off devices corresponding to 1's in bits 0-6
;_______________________________________________________________________________________
MSCPowerStatus
MOVEQ #0,D1
MOVE.L A0,-(SP)
MOVE.W #Unimplement,D0 ; does the _DockingDispatch trap exist?
_GetTrapAddress ,NEWTOOL
MOVEA.L A0,A1
MOVE.W @DockTrap,D0
_GetTrapAddress ,NEWTOOL
CMPA.L A0,A1
BEQ.S @NoDocking ; -> no, just turn internal power planes on/off
SUBQ.W #4,SP ; result
PEA dockPowerStatus ; docking selector = power status
CLR.L -(SP) ; params = nil
@DockTrap _DockingDispatch ; call the handler
ADDQ.W #4,SP ; toss the result
@NoDocking MOVEM.L (SP)+,D1/A0
MOVEA.L VIA2,A1 ; point to the base of the MSC
MOVEQ #(1<<pSCC) | (1<<pSerDrvr),D0 ; mask off the SCC power and serial drivers bits
AND.B D1,D0 ; are either of them set?
BEQ.S @NoSCC ; -> nope
EOR.B D0,D1 ; turn them both off
TST.B D1 ; turn power on or off?
BMI.S @TurnOnSCC
BCLR #MSCSCCClk,MSCClkCntl(A1) ; turn off SCC PCLK, RTXC
BRA.S @NoSCC
@TurnOnSCC BSET #MSCSCCClk,MSCClkCntl(A1) ; turn on SCC PCLK, RTXC
@NoSCC BTST #pHD,D1 ; is hard disk power being turned on/off?
BEQ.S @NoHD ; -> no
TST.B D1 ; turn power on or off?
BMI.S @TurnOnSCSI
BCLR #MSCSCSIReset,MSCClkCntl(A1) ; drive SCSI chip reset low to stop clocks
BRA.S @NoHD
@TurnOnSCSI BSET #MSCSCSIReset,MSCClkCntl(A1) ; drive SCSI chip reset high to start it up
@NoHD BCLR #pASC,D1 ; is sound power being turned on/off?
BEQ.S @NoSound ; -> nope
TST.B D1 ; turn power on or off?
BMI.S @TurnOnSnd
BCLR #MSCSndPower,MSCSndCntl(A1) ; turn off sound power
BRA.S @NoSound
@TurnOnSnd BSET #MSCSndPower,MSCSndCntl(A1) ; turn off sound power
@NoSound BCLR #pIWM,D1 ; clear the SWIM power bit
@NoSWIM MOVEQ #$7F,D0 ; return BNE if any bits are still set
AND.B D1,D0 ; so we can pass it on to the PMGR
BNE.S @MorePower ; -> more for the PMGR to do <H31>
CLR.W pmLength(A0) ; fix the returned length since we're done <H31>
@MorePower RTS
;_______________________________________________________________________________________
;
; Routine: MSCFakePowerStatus
;
; Inputs: A0 -- pointer to caller's parameter block
;
; Outputs: CCR-- always BNE
;
; Trashes: none
;
; Function: This is a skanky way of letting us call the Power Manager and getting control
; back to do further processing. This converts the powerRead+1 command sent
; by the PowerStatus routine above into a powerRead command so it can get the
; status PG&E knows about before filling in the rest of the bits that are now
; handled by the MSC. What can I say? The price of extensibility?
;_______________________________________________________________________________________
MSCFakePowerStatus
SUBQ.W #$1F-powerRead,pmCommand(A0) ; convert this to a powerRead command ($18)
RTS ; get here with BNE to send the command to the PMGR
;_______________________________________________________________________________________
;
; Routine: MSCSetSound
;
; Inputs: A0 -- pointer to caller's parameter block
;
; Outputs: D0 -- result code
; CCR-- BEQ if the call was emulated, else BNE
;
; Trashes: D1,A1
;
; Function: Emulates the soundSet call ($90) for systems that don't control sound
; power and latch with the PMGR micro. The send buffer will contain a
; byte with the following bits used:
;
; bit 0: 1=sound power enabled
; 1: 1=clear sound latch
;_______________________________________________________________________________________
MSCSetSound CLR.W pmLength(A0) ; no bytes returned
MOVEA.L pmSBuffer(A0),A1 ; point to the transmit buffer
MOVEQ #3,D1 ; mask off valid bits
AND.B (A1),D1
MOVEA.L VIA2,A1 ; get the MSC's base address
MOVE.B @MSCSound(D1),MSCSndCntl(A1) ; stuff the right value into the sound control register
MOVEQ #0,D0 ; return "no error"
RTS
; on MSC, the sound latch is cleared simply by accessing the sound control register
@MSCSound DC.B (0<<MSCSndPower)|(0<<MSCSndBusy) ; [0] do nothing
DC.B (1<<MSCSndPower)|(0<<MSCSndBusy) ; [1] just turn on sound power
DC.B (0<<MSCSndPower)|(1<<MSCSndBusy) ; [2] turn off sound power, clear sound latch
DC.B (1<<MSCSndPower)|(1<<MSCSndBusy) ; [3] turn on sound power, clear sound latch
;_______________________________________________________________________________________
;
; Routine: MSCReadSound
;
; Inputs: A0 -- pointer to caller's parameter block
;
; Outputs: D0 -- result code
; CCR-- BEQ if the call was emulated, else BNE
;
; Trashes: D1,A1
;
; Function: Emulates the soundRead call ($98) for systems that don't control sound
; power and latch with the PMGR micro. On exit, the send buffer will contain
; a byte with the following bits used:
;
; bit 0: 1=sound power is on
; 1: 1=sound latch is set
;_______________________________________________________________________________________
MSCReadSound
MOVEA.L VIA2,A1 ; get the MSC's base address
MOVEQ #(1<<mscSndBusy)|(1<<MSCSndPower),D1
AND.B MSCSndCntl(A1),D1 ; mask off sound busy and sound power bits
BCLR #mscSndBusy,D1 ; is the sound latch set?
BEQ.S @NoLatch
ADDQ.B #(1<<1),D1 ; yes, set bit 1=1
@NoLatch MOVE.W #1,pmLength(A0) ; 1 byte returned
MOVEA.L pmRBuffer(A0),A1 ; point to the receive buffer
MOVE.B D1,(A1) ; and stuff in the result
MOVEQ #0,D0 ; return "no error"
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CPUSpeedMSC
;
; Inputs: none
;
; Outputs: D0 - [maximum CPU speed][current CPU speed]
;
; Trashes: A0
;
; Function: returns the maximum and current (econo-mode or full) CPU speeds for
; MSC-based machines
;————————————————————————————————————————————————————————————————————————————————————————
CPUSpeedMSC MOVEA.L UnivInfoPtr,A0 ; point to our ProductInfo table
MOVEQ #7,D0 ; mask off the machine type from our CPU ID
AND.W CPUIDValue(A0),D0
MOVE.L @speedTable(D0.W*4),D0 ; get the maximum CPU speed in both halves <H9>
CMPI.W #CPUSpeed16MHz,D0 ; is this a 16MHz machine? <H9>
BLE.S @NoMSCEcono ; -> yes, econo-mode isn't supported <H9>
ADDA.L DecoderInfoPtr(A0),A0 ; point to our decoder table
MOVEA.L RBVAddr(A0),A0 ; then to the base of the MSC
BTST #MSCEconoBit,MSCConfig(A0) ; are we in econo-mode?
BEQ.S @NoMSCEcono ; -> nope <H8>
MOVE.W #CPUSpeed16MHz,D0 ; current speed is 16MHz
@NoMSCEcono RTS
@speedTable DC.W CPUSpeed33MHz, CPUSpeed33MHz ; ID=0 (boxYeager) <H71>
DC.W $484A , $5221 ; ID=1 (reserved HJR!) <H9>
DC.W CPUSpeed33MHz, CPUSpeed33MHz ; ID=2 (boxEscher) <H46>
DC.W CPUSpeed20MHz, CPUSpeed20MHz ; ID=3 (reserved-wasPenLite) <H71>
DC.W CPUSpeed25MHz, CPUSpeed25MHz ; ID=4 (boxDuo210) <H9>
DC.W CPUSpeed33MHz, CPUSpeed33MHz ; ID=5 (boxDuo230) <H9>
DC.W CPUSpeed16MHz, CPUSpeed16MHz ; ID=6 (boxDBLite16) <H9>
DC.W CPUSpeed16MHz, CPUSpeed16MHz ; ID=7 (reserved 16MHz) <H9>
;———————————————————————————————————————————————————————————————————————————————————————— <H56>
; Routine: ChangeCPUSpeedMSC
;
; Inputs: D1 - ≠0: switch to reduced speed, =0: switch to full speed
;
; Outputs: D0 - =1: speed was changed, =0: speed was not changed
;
; Trashes: D1, A0
;
; Function: switches the CPU speed based on the passed parameter, and returns 1 if the
; speed change was actually done
;————————————————————————————————————————————————————————————————————————————————————————
ChangeCPUSpeedMSC
MOVEA.L VIA2,A1 ; point to the MSC's configuration register
LEA MSCConfig(A1),A1
MOVEQ #~(1<<EconoBit),D0 ; mask out the econo-mode bit
AND.B (A1),D0 ; in the configuration register
OR.B D0,D1 ; OR in the new setting
CMP.B (A1),D1 ; are we changing the setting?
BEQ.S @NoChange ; -> no
MOVE.B D1,(A1) ; yes, write out the new setting
MOVEQ #CPUSpeedDisp,D0 ; get the current CPU speed
_PowerDispatch
BCLR #MSC25MHz,(A1) ; assume 33MHz
CMPI.W #CPUSpeed25MHz,D0 ; are we running at 25MHz or less?
BGT.S @SpeedChanged ; -> no, we're done
BSET #MSC25MHz,(A1) ; yes, optimize the state machines for slower speed
@SpeedChanged
MOVEQ #1,D0
RTS
@NoChange MOVEQ #0,D0
RTS
;———————————————————————————————————————————————————————————————————————————————————————— <H7>
; Routine: ClamshellVBL
;
; Inputs: A0 - pointer to VBL task queue element
;
; Outputs: none
;
; Trashes: D0,A0,A1
;
; Function: checks to see if the clamshell is closed, and if so, sets a flag so we can
; handle it at a _IdleMind time
;————————————————————————————————————————————————————————————————————————————————————————
ClamshellVBL
MOVE.W #ClamshellVBLFreq,vblCount(A0) ; reset the counter
MOVEA.L PMgrBase,A1 ; point to Power Manager variables
BTST #ignoreClamshell,PmgrFlags3(A1) ; what do we want to do? <H27>
BNE.S @InStation ; -> nothing <H27>
BTST #dockingStation,dockFlags(A1) ; are we in a docking station?
BNE.S @InStation ; -> yes, clamshell closed is OK
BTST #ClamshellClosed,PmgrFlags(A1) ; have we already detected the close?
BNE.S @Done ; -> yes, we're done this time
CLR.W -(SP)
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readExtSwitches,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; get the clamshell info
LEA pmRBuffer+4(SP),SP ; toss the parameter block
BTST #clamshell,(SP)+ ; is the clamshell closed?
BEQ.S @Done ; -> nope, all done
BSET #ClamshellClosed,PmgrFlags(A1) ; flag that the clamshell is closed
@Done RTS
@InStation BCLR #ClamshellClosed,PmgrFlags(A1) ; flag that the clamshell is open
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CheckClamshell (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: none
;
; Trashes: D0, A0
;
; Function: does the appropriate thing if the clamshell was closed (sleep or nothing),
; and then runs the "standard" countdown checking code
;————————————————————————————————————————————————————————————————————————————————————————
CheckClamshell
BTST #InSleep,PmgrFlags(A2) ; IF !InSleep THEN
BNE @Exit ;
CLR.W -(SP) ; Setup PB for PmgrCommand
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readExtSwitches,-(SP) ; pmCommand = ReadSwitch
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; get the clamshell info
LEA pmRBuffer+4(SP),SP ; toss the parameter block
BTST #clamshell,(SP)+ ; IF ClamShell Open THEN
BNE.S @doClamshellClosed ;
BCLR.B #ClamshellClosed,PmgrFlags(A2) ; flag that the clamshell is open
BRA RunIdleRoutinesProc ; ELSE
@doClamshellClosed
BTST.B #ignoreClamshell,PmgrFlags3(A2) ; IF ignore Clamshell THEN
BNE.S @Exit ; bail
BTST.B #dockingStation,dockFlags(A2) ; ELSE IF in a dockingstation THEN
BNE.S @Exit ; bail
BSR CurFrontProcEqual ; ELSE IF Processes <> THEN
BEQ.S @Exit ; bail
BSET.B #ClamshellClosed,PmgrFlags(A2) ; ELSE IF Clamshell = closed THEN
BNE.S @Exit ; bail
MOVE.B PmgrFlags(A2),-(SP) ; ELSE save PmgrFlags
BSET #AvoidNetDiag,PmgrFlags(A2) ; and set the no AppleTalk dialogs flag
MOVEQ #SleepNow,D0 ; force a sleep
_Sleep
BTST #AvoidNetDiag,(SP)+ ; was the no AppleTalk dialogs flag set before?
BEQ.S @NoDialog ; -> no, leave it alone
BSET #AvoidNetDiag,PmgrFlags(A2) ; yes, restore it
@NoDialog MOVE.L Ticks,LastAct(A2) ; waking updates last activity
@Exit BRA RunIdleRoutinesProc ; ENDIF
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SndWatchMSC
;
; Inputs: A0 - pointer to VBL task queue element
;
; Outputs: none
;
; Trashes: D0, A0, A2
;
; Function: A VBL task called once every ten seconds that checks the sound latch for
; ASC new use. If so then sound power is turned on. If power is already on
; then then the latch is cleared. If the latch stays clear for two VBLs then
; sound power is turned off.
;————————————————————————————————————————————————————————————————————————————————————————
SndWatchMSC MOVE.W #SndWFreq,vblCount(A0) ; reset the counter
MOVEA.L VIA2,A0 ; point to the MSC's sound control register
LEA MSCSndCntl(A0),A0
BTST #MSCSndBusy,(A0) ; was sound used in the last 10 sec
BNE.S @SoundOn ; -> yes
MOVEA.L PMgrBase,A2 ; no, sound's been on but now it's not
TST.B SysTaskFlag(A2) ; are the sound input primitives set up?
BEQ.S @NoSoundAct ; -> no, there can't be a sound input source selected
jsrTBL sndInputSource ; is a sound source selected?
TST.B D0
BNE.S @NoSound ; -> yes, sound input is active so don't power off sound
@NoSoundAct BCLR #MSCSndPower,(A0) ; turn off sound power
RTS
@SoundOn BSET #MSCSndPower,(A0) ; turn on sound power (latch is cleared by any register access)
_IdleUpdateDispatch
@NoSound RTS
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the volatile MSC chip registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveMSC MOVEA.L VIA2,A2 ; point to the base of the MSC
MOVEQ #$80-256,D0 ; save slot IER with bit 7 set so interrupts
OR.B MSCSlotIER(A2),D0 ; will be re-enabled upon wakeup
MOVE.B D0,-(SP)
MOVEQ #$80-256,D0 ; do the same with VIA2 IER
OR.B MSCVIA2IER(A2),D0
MOVE.B D0,-(SP)
BSET #MSCIOClk,MSCClkCntl(A2) ; make sure IOClk is on in case a bar's attached <H40>
MOVE.B MSCClkCntl(A2),-(SP) ; save the clock control register
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to have MSC turn off system power (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
MSCKillPower
MOVEA.L VIA2,A2 ; point to the power cycle/sleep register
ADDA.L #MSCPowerCycle,A2
MOVEQ #-1,D0
MOVE.L D0,(A2) ; write -1 to the register to kill the power
JMP (A1) ; we might optimistically get here
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the volatile MSC chip registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreMSC MOVEA.L VIA2,A2 ; point to the base of the MSC
MOVE.B (SP)+,MSCClkCntl(A2) ; restore volatile registers
MOVE.B (SP)+,MSCVIA2IER(A2)
MOVE.B (SP)+,MSCSlotIER(A2)
JMP (A1) ; and return
;———————————————————————————————————————————————————————————————————————————————————————— <H6>
; Wakeup routine to put the SCC into a known state (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
MSCInitSCC MOVEA.L VIA2,A2 ; turn on the internal SCC clock
BSET #MSCSCCClk,MSCClkCntl(A2)
MOVEA.L UnivInfoPtr,A2 ; point to the ProductInfo table
ADDA.L DecoderInfoPtr(A2),A2 ; then to the DecoderInfo table
MOVEM.L SCCRdAddr(A2),A2-A3 ; get the SCC base read/write addresses (channel B)
MOVEA.L VIA,A4 ; point to the VIA for delays
MOVE.B (A2),D0 ; do a read to make sure the SCC is synched up
TST.B (A4) ; delay a bit
MOVE.B #9,(A3) ; select register 9
TST.B (A4) ; delay some more
MOVE.B #$40,(A3) ; reset channel B
TST.B (A4) ; delay a little more
MOVEA.L VIA2,A2 ; turn off the internal SCC clock
BCLR #MSCSCCClk,MSCClkCntl(A2)
JMP (A1)
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: DBLiteModemType
;
; Input:
;
; Outputs: d0.l has the modem Type
;
; Trashes: d0
;
; Function: Returns type of modem installed in DBLite Modem
;
;————————————————————————————————————————————————————————————————————————————————————————
DBLiteModemType
moveq.l #ModemTypeDUO,d0 ; dbmodem
rts
ENDIF ; {hasMSC}
IF hasNiagra THEN
;•••••••••••••••••••••••••••••••••••••••• Niagra •••••••••••••••••••••••••••••••••••••••••
EXPORT NiagraPmgrPrims
ALIGN 4
DC.L PrimsTypeTable ; padding, for now
DC.L (NiagraPmgrPrimsEnd-NiagraPmgrPrims); size of table
NiagraPmgrPrims ; Table of Niagra Primitives Tables
DC.L NiagraRoutines-NiagraPmgrPrims ; offset to table of NiagraRoutines
DC.L NiagraPrimInfo-NiagraPmgrPrims ; offset to decoder-specific constants
DC.L NiagraIdleMindTable-NiagraPmgrPrims ; offset to table of Idlemind routines
DC.L NiagraSleepTable-NiagraPmgrPrims ; offset to table of sleep routines
DC.L NiagraWakeTable-NiagraPmgrPrims ; offset to table of wakeup routines
DC.L NiagraPMgrOpExceptions-NiagraPmgrPrims; offset to PMgrOp exception table
DC.L NiagraModemTable-NiagraPmgrPrims ; offset to Modem Table <H31>
DC.L PwrDispatchVects-NiagraPmgrPrims ; offset to power dispatch table
DC.L PMgrHookVects-NiagraPmgrPrims ; offset to PMgr hook table
DC.L CommsPowerTable-NiagraPmgrPrims ; offset to table of comms power routines <K12>
DC.L PMgrOpTbl-NiagraPmgrPrims ; offset to routine for PmgrOp
DC.L 0 ; offset to backlight tables
NiagraPmgrPrimsEnd
DC.L PrimsTypePtr ; flags
DC.L (NiagraRoutinesEnd-NiagraRoutines) ; size of table
NiagraRoutines ; Table of Niagra Specific Routines
DC.L PowerCycle030-NiagraRoutines ; offset to routine for power cycling down <H5>
DC.L Restore030-NiagraRoutines ; offset to routine for power cycling restore <H5>
DC.L BatWatch-NiagraRoutines ; offset to VBL task to check the battery level<H19>
DC.L GetLevel-NiagraRoutines ; offset to routine for determining battery level
DC.L LeadScaledBatteryInfo-NiagraRoutines; offset to routine to return scaled battery level <H15>
DC.L NiagraEnvInt-NiagraRoutines ; offset to environment interrupt handler
DC.L 0 ; no clamshellvbl
DC.L CPUSpeedNiagra-NiagraRoutines ; offset to routine for determining CPU speed
DC.L SndWatchPonti-NiagraRoutines ; offset to VBL task to check for sound usage <H19>
DC.L RedrawScrn-NiagraRoutines ; offset to routine for refreshing the screen <H17>
DC.L LeadAbsoluteBatteryVoltage-NiagraPmgrPrims; routine to return absolute battery level<H54>
DC.L 0 ; no routine to return info about battery times
DC.L 0 ; dynamic CPU speed change is not supported <H56>
NiagraRoutinesEnd
DC.L PrimsTypeInfo ; flags
DC.L (NiagraPrimInfoEnd-NiagraPrimInfo) ; size of table
NiagraPrimInfo ; machine-specific constants:
DC.B $46 ; PRAM base address <H14>
DC.B DefHysteresis ; default hysteresis
DC.B PMGRWARNLEVEL-STDOFFSET ; default low battery warning level <H5>
DC.B PMGRCUTOFF-STDOFFSET ; default dead battery warning level <H5>
DC.B PGMRWAKELEVEL-STDOFFSET ; hysteresis setting for pmgr wake level <H5>
DC.B (2-1) ; display shorted battery at second interrupt <H33>
DC.B 10 ; add 100mv to low bat warn if external video <H33>
DC.B 0 ; no charger features
DC.L $50FA0000 ; address of power cycling register <H7>
DC.L 0 |\ ; bitmap of Power Manager features <H52>
(0<<hasWakeupTimer) |\
(1<<hasSharedModemPort) |\
(1<<hasProcessorCycling) |\
(1<<mustProcessorCycle) |\
(1<<hasReducedSpeed) |\
(0<<dynamicSpeedChange) |\
(1<<hasSCSIDiskMode)
DC.L 0 |\ ; bitmap of private Power Manager features <H53>
(0<<hasExtdBattInfo) |\
(0<<hasBatteryID) |\
(0<<canSwitchPower)
DC.W 1 ; number of batteries
DC.B 0 ; Power Manager Parallel Interface
DC.B 0 ; padding for now
DC.L 0 ; no extended charge time
DC.B 0 ; value for power cycling register <K22>
DC.B 0 ; value for sleep register <K22>
DC.B 0 ; padding for now
DC.B 0 ; padding for now
NiagraPrimInfoEnd
DC.L PrimsTypePtr ; flags
DC.L (NiagraIdleMindTableEnd-NiagraIdleMindTable) ; size of table
NiagraIdleMindTable ; Machine specific Idlemind routines
DC.L CheckCountDownTimer-NiagraIdleMindTable ; offset to countdown timer
DC.L NiagraRunIdleRoutinesProc-NiagraIdleMindTable ; offset to run idle procs <H20>
DC.L ChkSleepTimeOut-NiagraIdleMindTable ; offset to check sleep
DC.L ChkIdle-NiagraIdleMindTable ; offset to check idle
DC.L CalcProgressive-NiagraIdleMindTable ; offset to calc progressive
DC.L GoPowerCycle-NiagraIdleMindTable ; offset to power cycle
NiagraIdleMindTableEnd
DC.L PrimsTypePtr ; flags
DC.L (NiagraSleepTableEnd-NiagraSleepTable) ; size of table
NiagraSleepTable ; list of routines to execute when going to sleep:
DC.L SleepHD-NiagraSleepTable ; sleep the hard drive if currently running
DC.L SaveVIA1-NiagraSleepTable ; save VIA1 registers
DC.L SaveASCBatmanDART-NiagraSleepTable ; save ASC/Batman registers <H29>
DC.L SoundPowerDownNiagra-NiagraSleepTable; power off sound <H29>
DC.L SaveFPU-NiagraSleepTable ; save FPU registers
DC.L SaveLCD-NiagraSleepTable ; save built-in LCD video registers
DC.L SaveVIA2-NiagraSleepTable ; save VIA2 registers
DC.L SendSleep-NiagraSleepTable ; send a sleep command
DC.L SaveSlp030-NiagraSleepTable ; save MMU registers
DC.L SaveSleepInfo-NiagraSleepTable ; save sleep info in video RAM
DC.L 0 ; (end of table)
NiagraSleepTableEnd
DC.L PrimsTypePtr ; flags
DC.L (NiagraWakeTableEnd-NiagraWakeTable) ; size of table
NiagraWakeTable ; list of routines to execute when waking up:
DC.L RestoreSlp030-NiagraWakeTable ; restore MMU, SPs, cache registers
DC.L RestoreVIA2-NiagraWakeTable ; restore VIA2 registers
DC.L RestoreLCD-NiagraWakeTable ; restore GSC (built-in LCD video) registers
DC.L RestoreFPU-NiagraWakeTable ; restore FPU registers
DC.L RestoreASCBatman-NiagraWakeTable ; restore ASC and Batman registers
DC.L RestoreDartAmp-NiagraWakeTable ; turn on amps <H29>
DC.L RestoreVIA1-NiagraWakeTable ; restore VIA1 registers
DC.L RestorePmgrMisc-NiagraWakeTable ; restore Misc PmgrVars
DC.L DockingWakeup-NiagraWakeTable ; restore state of currently connected bar <H10>
DC.L WakeClrInts-NiagraWakeTable ; clear any pending PmgrInterrupts
DC.L WakeSoundSetNiagra-NiagraWakeTable ; set state for sound out of sleep
DC.L 0 ; (end of table)
NiagraWakeTableEnd
DC.L PrimsTypePMgrEx ; flags
DC.L (NiagraPMgrOpExceptionsEnd-NiagraPMgrOpExceptions) ; size of table
NiagraPMgrOpExceptions ; PMgrOp exceptions:
DC.B $F0,$50 ; $5x - modem commands
DC.L DartModemCmds-* ;
DC.B $F7,$71 ; $71,$79 - modem commands
DC.L DartSPI-* ;
DC.B $F0,$A0 ; $Ax - modem commands
DC.L DartSPI-* ;
DC.W 0 ; (end of table)
NiagraPMgrOpExceptionsEnd
DC.L PrimsTypePtr ; flags
DC.L (NiagraModemTableEnd-NiagraModemTable) ; size of table
NiagraModemTable
DC.L DartModemOn-NiagraModemTable ; offset to routine to turn on modem
DC.L DartModemOff-NiagraModemTable ; offset to routine to turn off modem
DC.L DartModemType-NiagraModemTable ; offset to routine to get modem type <K10>
NiagraModemTableEnd
ALIGN 4
;————————————————————————————————————————————————————————————————————————————————
; Routine: DartModemCmds
;
; Input: A0 - points the pmgrop PB
;
; Destroys: d1
;
; Called by: Bra from NewPmgrOp
;
; Function: filter the modem $5X commands, $50 should still go the power manager
;————————————————————————————————————————————————————————————————————————————————
DartModemCmds
cmp.w #modemSet,pmCommand(A0)
bne.s DartSPI ; Handle call through SPI
moveq #1,d1 ; set CC to not handled here
rts ; return
;————————————————————————————————————————————————————————————————————————————————
; Routine: DartSPI <H16>
;
; Input: A0 - points the pmgrop PB
;
; Destroys: d1
;
; Called by: Bra from NewPmgrOp
;
; Function: transfer data through new SPI port
;————————————————————————————————————————————————————————————————————————————————
DartSPI
@savedRegs REG D1-D4/A0-A3
; ----- dynamic test for SPI ----
movea.l PMgrBase,a3 ; point to the Power Manager's variables
btst.b #PmgrDartSPI,PmgrFlags1(a3) ; test if SPI modem installed
bne.s @SPIStart ; Handle call through SPI
moveq #1,d1 ; set CC to not handled here
rts ; return
@SPIStart
movem.l @savedRegs,-(sp)
MOVEA.L UnivInfoPtr,a2 ; point to the ProductInfo table,
ADDA.L DecoderInfoPtr(a2),a2 ; then to the DecoderInfo table,
MOVEA.L JAWSAddr(a2),a2 ; then to the Niagra base address,
ADDA.L #NiagraGUR,a2 ; point to the base of the GUR space
; ----- send command and count ----
move.w pmCommand(a0),d3
move.w d3,d1
bsr SendSPI ; send command byte
bne.s @PMgrOpExit ; exit if error returned
MOVEA.L PMgrBase,A1 ; point to the Power Manager's variables
MOVEA.L vSendCountTbl(A1),A1 ; and get the send count table
move.w pmLength(a0),d2 ; pop the count into d2
tst.b (a1,d3)
bpl.s @noCount ; if positive, no count
move.w d2,d1
bsr SendSPI ; send count byte
bne.s @PMgrOpExit ; exit if error returned
; ----- send data ----
@noCount movea.l pmSBuffer(a0),a3 ; 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 (a3)+,D1 ; get the next data byte
BSR SendSPI ; and send it
@StartSend DBNE d2,@SendData ; -> more bytes to send
BNE.S @PMgrOpExit ; -> error
; ----- receive data -----
MOVEA.L PMgrBase,A1 ; point to the Power Manager's variables
MOVEA.L vRecvCountTbl(A1),A1 ; and get the receive count table
clr.l d4 ; clear count register
move.b (a1,d3),d4 ; initialize to count
bmi.s @readReplyCount ; (<0)
cmp.b #1,d4 ; test against 1
ble.s @readData ; if ( =0 or =1 ) go to read
subq #1,d4 ; (>1) correct count
bra.s @readData ; if 0 or 1 go to read
@readReplyCount
bsr ReceiveSPI ; read first byte for receive count
bne.s @PMgrOpExit ; exit if error returned
move.w d1,d4 ; move count into d4
@readData ; d4 has receive byte count
movea.l pmRBuffer(a0),a3 ; a3 new points
move.w d4,pmLength(a0) ;
bra.s @StartReceive ; start receiving data
@ReceiveByte
bsr.s ReceiveSPI ; read a byte into d1
bne.s @PMgrOpExit ; -> error
move.b d1,(a3)+ ; move data byte into buffer
@StartReceive
dbra d4,@ReceiveByte ; -> more bytes to send
@PMgrOpExit
moveq #0,d1 ; indicate we handled call
@exit
movem.l (sp)+,@savedRegs ; restore working registers
rts
;————————————————————————————————————————————————————————————————————————————————
; Routine: WaitSPIAckHi
;
; Input: a2.l - pointer to GUR space
;
; Returns CCR - BNE if ACK went hi, BEQ if timed out
;
; Function: wait for SPI ack high
;————————————————————————————————————————————————————————————————————————————————
WaitSPIAckHi
@workRegs reg D1-d2
movem.l @workRegs,-(sp) ; save working set
moveq #32,d2 ; loop to max 32 msec
@nextmsec move.w timedbra,d1 ; 1 msec count
@waitAckhi btst.b #PontiSPIAck,PontiSPIMdmCtl(a2) ; test ack
dbne d1,@waitAckhi ; loop for upto 1 msec
dbne d2,@nextmsec ; loop for d2 msec
movem.l (sp)+,@workRegs
rts
;————————————————————————————————————————————————————————————————————————————————
; Routine: WaitSPIAckLo
;
; Input: a2 - pointer to GUR space
;
; Returns CCR - BEQ if ACK went lo, BNE if timed out
;
; Function: wait for SPI ack lo
;————————————————————————————————————————————————————————————————————————————————
WaitSPIAckLo
@workRegs reg D1-d2
movem.l @workRegs,-(sp) ; save working set
moveq #32,d2 ; loop to max 32 msec
@nextmsec move.w timedbra,d1 ; 1 msec count
@waitAcklo btst.b #PontiSPIAck,PontiSPIMdmCtl(a2) ; test ack
dbeq d1,@waitAcklo ; loop for upto 1 msec
dbeq d2,@nextmsec ; loop for d2 msec
movem.l (sp)+,@workRegs
rts
;————————————————————————————————————————————————————————————————————————————————
; Routine: SendSPI
;
; Input: a2.l - pointer to GUR space
; d1.b - byte to send
;
; Returns d0.w - 0 = ok, non-zero = error
;
; Function: send a byte thru the SPI
;————————————————————————————————————————————————————————————————————————————————
SendSPI MOVE.W #pmSendStartErr,D0 ; assume a send error
bsr.s WaitSPIAckHi ; (1) wait for pmgr idle
beq.s @error ; if bit low, error
;begin transaction
bset.b #PontiLmpSPIDir,PontiLmpSftCtl(a2) ; (2) set direction to output
move.b d1,PontiSPISftReg(a2) ; (3) write data
bclr.b #PontiSPIReq,PontiSPIMdmCtl(a2) ; (4) assert data valid
bsr.s WaitSPIAckLo ; (5) --> modem shift data
; (6) wait for data accepted
bne.s @error ; if bit low, error
bset.b #PontiSPIReq,PontiSPIMdmCtl(a2) ; (7) clear data valid
MOVEQ #noErr,D0 ; report no error
@error tst.w d0
rts
;————————————————————————————————————————————————————————————————————————————————
; Routine: ReceiveSPI
;
; Input: a2.l - pointer to GUR space
; d1.b - byte to send
;
; Returns d0.w - 0 = ok, non-zero = error
;
; Function: read a byte from the spi
;————————————————————————————————————————————————————————————————————————————————
ReceiveSPI MOVE.W #pmRecvStartErr,D0 ; assume a receive error
bsr.s WaitSPIAckHi ; (1) wait for pmgr idle
beq.s @error ; if bit low, error
;begin transaction
bclr.b #PontiLmpSPIDir,PontiLmpSftCtl(a2) ; (2) set direction to input
bclr.b #PontiSPIReq,PontiSPIMdmCtl(a2) ; (3) (RFD) ready for data
bsr.s WaitSPIAckLo ; (4) acknowledge req
; (5) <-- modem shifting
bne.s @error ; if bit low, error
bset.b #PontiSPIReq,PontiSPIMdmCtl(a2) ; (6) acknowledge ack
bsr.s WaitSPIAckHi ; (7) wait (DAV)
beq.s @error ; if bit low, error
move.b PontiSPISftReg(a2),d1 ; (8) read data
MOVEQ #noErr,D0 ; report no error
@error tst.w d0
rts
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CPUSpeedNiagra
;
; Inputs: none
;
; Outputs: D0 - [maximum CPU speed][current CPU speed]
;
; Trashes: D1, A0
;
; Function: returns the maximum and current (econo-mode or full) CPU speeds for
; Niagra-based machines
;————————————————————————————————————————————————————————————————————————————————————————
CPUSpeedNiagra
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 JAWS base address,
ADDA.L #NiagraSpeedReg,A0 ; and finally to the CPU clock register
MOVEQ #%00000011,D1 ; only care about last two bits
AND.B (A0),D1 ;
LSL.B #2,D1 ; convert to long words
MOVE.L @CPUSpeedNiagraTable(D1.W),D0 ; get our table entry
ADDA.L #JAWSEconoMode-NiagraSpeedReg,A0; (point to the econo-mode register)
BTST #1,(A0) ; IF inEconoMode THEN
BNE.S @InEcono ; Exit we're done
MOVE.W @CPUSpeedNiagraTable(D1.W),D0 ; Else we are running full speed
@InEcono RTS
@CPUSpeedNiagraTable
DC.W CPUSpeed16MHz,CPUSpeed16MHz
DC.W CPUSpeed20MHz,CPUSpeed16MHz
DC.W CPUSpeed25MHz,CPUSpeed16MHz
DC.W CPUSpeed33MHz,CPUSpeed16MHz
ALIGN 4
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: NiagraRunIdleRoutinesProc (IdleMind) <H20>
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: none
;
; Trashes: D0, A0
;
; Function: does the appropriate thing if the shutdown request bit is set
;————————————————————————————————————————————————————————————————————————————————————————
NiagraRunIdleRoutinesProc
btst.b #PmgrShutdownReq,PmgrFlags1(A2) ; test request
BEQ.S @exitSoftReset ; exit if no request
movea.l vSoftShutdown(a2),a0 ;
jsr (a0) ; call shutdown vector
bne.s @exitSoftReset ; if error, don't clear flag
bclr.b #PmgrShutdownReq,PmgrFlags1(A2) ; clear request
@exitSoftReset
; Convienient place to check whether a notification message must be posted regarding <H34>
; the use of external video and the charger. If the user boots or wakes the machine |
; with an external monitor but no charger, then external video will be disabled by the v
; primaryInit code. PrimaryInit will also set the flag "PmgrExtVidAlrt" indicating
; the condition for a warning to be posted. If while external video is on, and the
; charger is disconnected, a different warning should be posted about the hardware
; becoming unstable unless the charger is attached.
BCLR #PmgrExtVidAlrt,PmgrFlags1(A2) ; IF AlertUser THEN
BEQ.S @NoVidAlrt ; .
MOVE.L NoVidSTRPtr(a2),a0 ; Load Appropriate String
MOVEQ #1,d0 ; Tell Message Handler to use completion routine
BRA.S @postMsg ; Post Message
@NoVidAlrt
BTST #PmgrExtVidOn,PmgrFlags1(a2) ; IF External Video THEN
BEQ.S @Cont ; .
BTST #HasCharger,Charger(a2) ; IF ChargerNotConnected THEN
BNE.S @clearFlag ; .
MOVE.L NoChrgrSTRPtr(a2),a0 ; Get handle to alert string
MOVEQ #0,d0 ; Set empty completion routine
@postMsg BSR PostUserNmMsg ; Post the notification mgr message
BRA.S @Cont
@clearFlag ; ELSE
BTST #PmgrAvoidUsrMsg,PmgrFlags1(a2) ; IF warning messages enabled THEN
BEQ.S @Cont ; .
LEA UNmQEntry(a2),a0 ; Get address of notification record
_NMRemove ; Remove Message
BCLR #PmgrAvoidUsrMsg,PmgrFlags1(a2) ; after doing NMRemove then clr flag (steve)
@Cont BRA RunIdleRoutinesProc ; Continue with RunIdle
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: DartModemOn
;
; Input: a0.l = ptr to powermanager pb + 4 byte general data buffer
; d1.b = modem status bits from power manager
;
; Outputs: condition codes
;
; Trashes: d0
;
; Function: turn Power on to the internal dartanian modem
;
;————————————————————————————————————————————————————————————————————————————————————————
DartModemOn
bsr StdModemOn ; turn on the modem the standard way
; test for spi
move.l a2,-(sp) ; save a2
movea.l UnivInfoPtr,a2 ; point to the ProductInfo table,
adda.l DecoderInfoPtr(a2),a2 ; then to the DecoderInfo table,
movea.l JAWSAddr(a2),a2 ; then to the Niagra base address,
adda.l #NiagraGUR,a2 ; and finally general utility register space
;
bclr.b #PmgrDartSPI, \ ;
([PmgrBase],PmgrFlags1) ; preset - disable spi interface
btst.b #PontiSPIMdmId,PontiSPIMdmCtl(a2); check the new modem interface bit (spi)
beq.s @exitSPI ; if not set, old modem, exit CCR set
bset.b #PmgrDartSPI,\
([PmgrBase],PmgrFlags1) ; enable spi interface
bclr.b #PontiSndSPIIrqMsk,PontiSndCtl(a2); enable spi interrupts
moveq.l #1,d0 ; set CCR, don't turn on power to SCC
@exitSPI move.l (sp)+,a2 ; restore a2
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: DartModemOff
;
; Input: a0.l = ptr to powermanager pb + 4 byte general data buffer
; d1.b = modem status bits from power manager
;
; Outputs: none
;
; Trashes: d0
;
; Function: turn Power off to the internal dartanian modem
;
;————————————————————————————————————————————————————————————————————————————————————————
DartModemOff ;
move.l a2,-(sp) ; save a2
movea.l UnivInfoPtr,a2 ; point to the ProductInfo table,
adda.l DecoderInfoPtr(a2),a2 ; then to the DecoderInfo table,
movea.l JAWSAddr(a2),a2 ; then to the Niagra base address,
adda.l #NiagraGUR+PontiSndCtl,a2 ; and finally to the modem register
bclr.b #PmgrDartSPI,\
([PmgrBase],PmgrFlags1) ; disable spi interface
bset.b #PontiSndSPIIrqMsk,(a2) ; disable spi interrupts
bsr StdModemOff ; power off modem the standard way
move.l (sp)+,a2 ; restore a2
RTS
;———————————————————————————————————————————————————————————————————————————————————————— <K10>
; Routine: DartModemType
;
; Input:
;
; Outputs: d0.l has the modem Type
;
; Trashes: d0
;
; Function: Returns type of modem installed in Dartanian Modem
;
;————————————————————————————————————————————————————————————————————————————————————————
DartModemType
move.l a0,-(sp)
moveq.l #ModemTypeSerial,d0 ; assume serialmodem
movea.l UnivInfoPtr, a0 ; point to product info table,
movea.l DecoderInfoPtr(a0), a0 ; then to the DecoderInfo table,
movea.l JAWSAddr(a0),a0 ; then to the Niagra base address,
adda.l #NiagraGUR+PontiSPIMdmCtl, a0 ; and finally to the modem ctl register
btst.b #PontiSPIMdmId,(a0) ; test the modem bit
beq.s @exit
moveq.l #ModemTypeDUOPlus,d0 ; load new modem id
@exit movem.l (sp)+,a0
rts
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SndWatchPonti
;
; Inputs: A0 - pointer to VBL task queue element
;
; Outputs: none
;
; Trashes: D0, A0, A2
;
; Function: A VBL task called once every ten seconds that checks the sound latch for
; ASC new use. If so then sound power is turned on. If power is already on
; then then the latch is cleared. If the latch stays clear for two VBLs then
; sound power is turned off.
;————————————————————————————————————————————————————————————————————————————————————————
SndWatchPonti
MOVE.W #SndWFreq,vblCount(A0) ; reset the counter
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 ; and finally to the sound register
BTST #PontiSndLatchData,(A0) ; was sound used in the last 10 sec
BNE.S @SoundOn ; -> yes
MOVEA.L PMgrBase,A2 ; no, sound's been on but now it's not
TST.B SysTaskFlag(A2) ; are the sound input primitives set up?
BEQ.S @NoSoundAct ; -> no, there can't be a sound input source selected
jsrTBL sndInputSource ; is a sound source selected?
TST.B D0
BNE.S @NoSound ; -> yes, sound input is active so don't power off sound
@NoSoundAct BCLR #PontiSndPwrOn,(A0) ; turn off sound power
RTS
@SoundOn BSET #PontiSndPwrOn,(A0) ; turn on sound power
BSET #PontiSndLatchClr,(A0) ; pulse (positive) latch clear bit
BCLR #PontiSndLatchClr,(A0)
_IdleUpdateDispatch
@NoSound RTS
;________________________________________________________________________________________
;
; Routine: NiagraEnvInt
;
; Inputs: A0 - pointer to PMGR interrupt data: [flags][battery][gas][therm]
; A1 - pointer to VIA1 base
; A2 - pointer to Power Manager's variables
;
; Outputs: none
;
; Trashes: none (D0-D3 and A0-A3 are preserved by the interrupt dispatcher)
;
; Function: Handles PMGR environment interrupts by attempting a soft shutdown, if allowed.
;________________________________________________________________________________________
NiagraEnvInt
_IdleUpdateDispatch
btst.b #ScsiDiskModeOn,PmgrFlags(a2) ; check for scsi disk mode
beq.s @normalRequest ; if not, continue
_PowerOff ; ... else power off
bra.s * ; ... wait for the plug
@normalRequest
btst.b #PmgrShutdownEnb,PmgrFlags1(a2) ; is shutdown allowed
beq.s @exit ; if not just exit
bset.b #PmgrShutdownReq,PmgrFlags1(a2) ; set shutdown request
@exit rts
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to poweroff Sound (A1 = return address) <H29>
;———————————————————————————————————————————————————————————————————————————————————————— |
SoundPowerDownNiagra ; V
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 ; and finally to the sound register
;
BSET #PontiSndLatchClr,(A0) ; pulse (positive) latch clear bit
BCLR #PontiSndLatchClr,(A0) ;
;
BCLR #PontiSndPwrOn,(A0) ; turn off sound power
;
JMP (A1) ; and return
ENDIF ; {hasNiagra} IF hasNiagra THEN
IF hasPratt THEN
;•••••••••••••••••••••••••••••••••••••••• Pratt •••••••••••••••••••••••••••••••••••••••••
EXPORT PrattPmgrPrims
import PrattBkltPrims
ALIGN 4
DC.L PrimsTypeTable ; flags
DC.L (PrattPmgrPrimsEnd-PrattPmgrPrims) ; size of table
PrattPmgrPrims ; Table of Primitives tables
DC.L PrattRoutines-PrattPmgrPrims ; offset to table of Pratt routines
DC.L PrattPrimInfo-PrattPmgrPrims ; offset to decoder-specific constants
DC.L PrattIdleMindTable-PrattPmgrPrims ; offset to table of Idlemind routines
DC.L PrattSleepTable-PrattPmgrPrims ; offset to table of sleep routines
DC.L PrattWakeTable-PrattPmgrPrims ; offset to table of wakeup routines
DC.L PrattPMgrOpExceptions-PrattPmgrPrims; offset to PMgrOp exception table
DC.L PrattModemTable-PrattPmgrPrims ; offset to table of modem routines
DC.L PwrDispatchVects-PrattPmgrPrims ; offset to table of PwrDispatchVects
DC.L PMgrHookVects-PrattPmgrPrims ; offset to table of PmgrMgr Hooks
DC.L PrattCommsPowerTable-PrattPmgrPrims ; offset to table of comms power routines <K12>
DC.L PMgrOpTbl-PrattPmgrPrims ; offset to table for PmgrOp
DC.L PrattBkltPrims-PrattPmgrPrims ; offset to backlight tables
PrattPmgrPrimsEnd
DC.L PrimsTypePtr ; flags
DC.L (PrattRoutinesEnd-PrattRoutines) ; size of table
PrattRoutines ; machine-specific routines
DC.L PowerCycle040-PrattRoutines ; offset to routine for power cycling
DC.L Restore040-PrattRoutines ; offset to routine for power cycling restore
DC.L BatWatch-PrattRoutines ; offset to VBL task to check the battery level
DC.L GetExtLevelPratt-PrattRoutines ; offset to routine for determining battery level
DC.L MultiScaledBatteryInfo-PrattRoutines; offset to routine to return scaled battery level
DC.L 0 ; no environment interrupts
DC.L CPUSpeedMSC-PrattRoutines ; offset to routine for determining CPU speed
DC.L SndWatchPratt-PrattRoutines ; offset to VBL task to check for sound usage
DC.L RedrawScrn-PrattRoutines ; offset to routine for refreshing the screen
DC.L PGEAbsoluteBatteryVoltage-PrattRoutines ; routine to return absolute battery level <H54>
DC.L PrattGetBatteryTimes-PrattRoutines ; routine to return info about battery times
DC.L 0 ; dynamic CPU speed change is not supported
PrattRoutinesEnd
DC.L PrimsTypeInfo ; flags
DC.L (PrattPrimInfoEnd-PrattPrimInfo) ; size of table
PrattPrimInfo ; machine-specific constants:
DC.B $46 ; PRAM base address
DC.B DefHysteresis ; default hysteresis
DC.B 40 ; default low battery warning level (20%)
DC.B 10 ; default dead battery warning level (5%)
DC.B 0 ; hysteresis setting for wake level (none)
DC.B 0 ; shorted battery at first interrupt (none)
DC.B 0 ; no external video correction needed
DC.B 0 ; no charger features
DC.L $5008001B ; address of power cycling register
DC.L 0 |\ ; bitmap of Power Manager features
(0<<hasWakeupTimer) |\
(1<<hasSharedModemPort) |\
(1<<hasProcessorCycling) |\
(1<<mustProcessorCycle) |\
(0<<hasReducedSpeed) |\
(0<<dynamicSpeedChange) |\
(1<<hasSCSIDiskMode)
DC.L 0 |\ ; bitmap of private Power Manager features <H53>
(1<<hasExtdBattInfo) |\
(1<<hasBatteryID) |\
(0<<canSwitchPower)
DC.W 1 ; number of batteries
DC.B 2 ; Power Manager Serial Interface
DC.B 0 ; padding for now
DC.L 0 ; no extended charging
DC.B $01 ; value for power cycling register <K22>
DC.B 0 ; value for sleep register <K22>
DC.B 0 ; padding for now
DC.B 0 ; padding for now
PrattPrimInfoEnd
DC.L PrimsTypePtr ; flags
DC.L (PrattIdleMindTableEnd-PrattIdleMindTable) ; size of table
PrattIdleMindTable ; machine specific IdleMind Routines
DC.L CheckCountDownTimer-PrattIdleMindTable; offset to count down timer
DC.L CheckClamshell-PrattIdleMindTable ; offset to clam shell
DC.L ChkSleepTimeOut-PrattIdleMindTable ; offset to sleep time out
DC.L ChkIdle-PrattIdleMindTable ; offset to check idle
DC.L CalcProgressive-PrattIdleMindTable ; offset to calc progressive
DC.L GoPowerCycle-PrattIdleMindTable ; offset to go power cycle
PrattIdleMindTableEnd
DC.L PrimsTypePtr ; flags
DC.L (PrattSleepTableEnd-PrattSleepTable); size of table
PrattSleepTable ; list of routines to execute when going to sleep:
DC.L SleepHD-PrattSleepTable ; sleep the hard drive if currently running
DC.L DockingSleep-PrattSleepTable ; save state of currently connected bar
DC.L EnetSleep-PrattSleepTable ; sleep the onboard Enet <K17>
DC.L SaveLCD-PrattSleepTable ; save GSC (built-in LCD video) registers
DC.L SaveFPU-PrattSleepTable ; save FPU registers
DC.L SaveVIA1-PrattSleepTable ; save VIA1 registers
DC.L SaveVIA2-PrattSleepTable ; save VIA2 registers
DC.L SaveWhitney-PrattSleepTable ; save Whitney registers
DC.L SaveSlp040-PrattSleepTable ; save MMU registers
DC.L SaveSleepInfo-PrattSleepTable ; save sleep info in Power Manager globals
DC.L SendSleep-PrattSleepTable ; send a sleep command
DC.L 0 ; (end of table)
PrattSleepTableEnd
DC.L PrimsTypePtr ; flags
DC.L (PrattWakeTableEnd-PrattWakeTable) ; size of table
PrattWakeTable ; list of routines to execute when waking up:
DC.L RestoreSlp040-PrattWakeTable ; restore MMU, SPs, cache registers
DC.L RestoreWhitney-PrattWakeTable ; restore Whitney registers
DC.L RestoreVIA2-PrattWakeTable ; restore VIA2 registers
DC.L RestoreVIA1-PrattWakeTable ; restore VIA1 registers
DC.L RestoreFPU-PrattWakeTable ; restore FPU registers
DC.L RestoreLCD-PrattWakeTable ; restore CSC (built-in LCD video) registers
DC.L EnetWake-PrattWakeTable ; wake the onboard Enet <K17>
DC.L DockingWakeup-PrattWakeTable ; restore state of currently connected bar
DC.L WakeClrInts-PrattWakeTable ; clear any pending PmgrInterrupts
DC.L 0 ; (end of table)
PrattWakeTableEnd
DC.L PrimsTypePMgrEx ; flags
DC.L (PrattPMgrOpExceptionsEnd-PrattPMgrOpExceptions) ; size of table
PrattPMgrOpExceptions ; PMgrOp exceptions:
DC.B $F7,SetModemInts ; $71,$79 - modem commands
DC.L PrattModemOp-* ;
DC.W 0 ; none for the moment
PrattPMgrOpExceptionsEnd
DC.L PrimsTypePtr ; flags <K10>
DC.L (PrattModemTableEnd-PrattModemTable); size of table
PrattModemTable
DC.L 0 ; offset to routine to turn on modem
DC.L 0 ; offset to routine to turn off modem
DC.L BlackBirdModemType-PrattModemTable ; offset to routine to get modem type
PrattModemTableEnd
DC.L PrimsTypePtr ; flags <K12>
DC.L (PrattCommsPowerTableEnd-PrattCommsPowerTable); number of entries
PrattCommsPowerTable
@PwrOn DC.L 0 ; no Port B serial
DC.L PrattPortAOn-PrattCommsPowerTable ; A serial
DC.L PortCOn-PrattCommsPowerTable ; C serial (internal modem)
DC.L PrattSonicOn-PrattCommsPowerTable ; onboard ethernet
@PwrOff DC.L 0 ; no Port B serial
DC.L PrattPortAOff-PrattCommsPowerTable ; A serial
DC.L PortCOff-PrattCommsPowerTable ; C serial (internal modem)
DC.L PrattSonicOff-PrattCommsPowerTable ; onboard ethernet
PrattCommsPowerTableEnd
ALIGN 4
ENDIF
;———————————————————————————————————————————————————————————————————————————————————————— <K26> thru
; Routine: GetExtLevelPratt |
; v
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - normalized battery level (-1 to 4)
; CCR - BNE if a valid battery level is being returned
;
; Trashes: D0-D3, A0
;
; Function: Reads the extended battery power level from the Power Manager (which is
; pre-averaged by the PMGR). Next, the value is compared with the warning
; and cutoff values in the globals. Warning being the first alert, midway from
; warning to cutoff being the second, and the cutoff being the 10 second
; countdown.
;
; Note: The extended battery status command supports a word-sized battery
; level. Currently the PMGR on Blackbird returns a value in half
; percentages, that is from 0-200.
;————————————————————————————————————————————————————————————————————————————————————————
GetExtLevelPratt
CLR.L -(SP)
CLR.L -(SP)
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readExtBatt,-(SP) ; pmCommand = get extended battery data
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVEA.L SP,A0 ; point to the buffer
MOVEQ #%00001011,D0 ; mask off the bits we want in the flags byte,
AND.B (A0),D0
MOVE.B Charger(A2),D1 ; get the old charger state,
MOVE.B D0,Charger(A2) ; and save the new charger state
MOVE.B (A0)+,D0 ; get the unmodified flags
EOR.B D0,D1 ; has the charger state changed since last time?
BTST #HasCharger,D1 ;
BEQ.S @ChargeSame ; -> no
ST TOdirtyFlag(A2) ; yes, flag that timeouts need updating
@ChargeSame MOVE.W (A0),D3
MOVE.B D3,BatAvg(A2) ; save the 8-bit battery voltage
ADDQ.W #8,SP ; toss the buffer
BTST #HasCharger,D0 ; is a charger connected?
BNE.S @HaveCharger ; -> yes, we don't care about the battery level
BTST #2,D0 ; is a battery connected?
BEQ.S @HaveCharger ; -> no, don't bother with battery level
MOVEQ #0,D0 ; level 0
CMP.B LowWarn(A2),D3 ;
BHI.S @foundlevel
MOVEQ #1,D0 ; level 1
MOVEQ #0,D1 ; clr register
MOVE.B LowWarn(A2),D1 ; get low-warning level
ADD.B CutOff(A2),D1 ; add cutoff
LSR.B #1,D1 ; average the two
CMP.B D1,D3 ; are we there yet?
BHI.S @foundlevel ;
MOVEQ #3,D0 ; level 3
CMP.B CutOff(A2),D3 ; are we at cutoff yet?
BHI.S @foundlevel ;
MOVEQ #4,D0 ; level 4
BRA.S @foundlevel ; 10 second countdown
@HaveCharger
MOVEQ #-1,D0 ; return a "charged" battery level in case someone cares
@foundlevel MOVEQ #1,D1 ; always return BNE for data valid
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SndWatchPratt
;
; Inputs: A0 - pointer to VBL task queue element
;
; Outputs: none
;
; Trashes: D0, A0, A2
;
; Function: A VBL task called once every ten seconds that checks the sound latch for
; ASC new use. If so then sound power is turned on. If power is already on
; then then the latch is cleared. If the latch stays clear for two VBLs then
; sound power is turned off.
;————————————————————————————————————————————————————————————————————————————————————————
SndWatchPratt
MOVE.W #SndWFreq,vblCount(A0) ; reset the counter
MOVEA.L ASCBase,A0 ; point to the ProductInfo table,
LEA wSndControl(A0),A0 ; A0 = Ptr to Sound Control Register
BTST #wSingerSNDFlag,(A0) ; IF wSingerSNDFlag THEN
BNE.S @SoundOn ; there was a sound in the last 10 sec
MOVEA.L PMgrBase,A2 ; no, sound's been on but now it's not
TST.B SysTaskFlag(A2) ; are the sound input primitives set up?
BEQ.S @NoSoundAct ; -> no, there can't be a sound input source selected
jsrTBL sndInputSource ; is a sound source selected?
TST.B D0
BNE.S @NoSound ; -> yes, sound input is active so don't power off sound
@NoSoundAct BCLR #wSingerPower,(A0) ; turn off sound power
RTS
@SoundOn BSET #wSingerPower,(A0) ; turn on sound power
BSET #wSingerSNDFlag,(A0) ; Clear the latch
_IdleUpdateDispatch ;
@NoSound RTS ; <K26>
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: PrattGetBatteryTimes
;
; Inputs: - pointer to BatteryTimeRec record:
; expectedBatteryTime DS.L 1 ; estimated battery time remaining
; minimumBatteryTime DS.L 1 ; minimum battery time remaining
; maximumBatteryTime DS.L 1 ; maximum battery time remaining
; timeUntilCharged DS.L 1 ; time remaining until the battery is fully charged
; D0 - high word: system total (0) - battery number (1-n)
;
; Outputs: none
;
; Trashes: A0-A1, D0-D2
;
; Function: fills in a record containing fields that describe battery times.
;________________________________________________________________________________________
PrattGetBatteryTimes
@NoBattery CLR.L (A0)+ ; zero out the fields
CLR.L (A0)+
CLR.L (A0)+
CLR.L (A0)+
MOVEQ #0,D0
RTS
;————————————————————————————————————————————————————————————————————————————————
; Routine: PrattModemOp
;
; Input: A0 - points the pmgrop PB
;
; Destroys: d1
;
; Called by: PmgrOp
;
; Function: transfer data through modem
;————————————————————————————————————————————————————————————————————————————————
PrattModemOp
moveq #1,d1 ; set CC to not handled here
rts ; return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the Whitney registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveWhitney
MOVEA.L ASCBase,A2 ; point to the base of the ASC/Batman
MOVE.B ascMode(A2),-(SP) ; save the chip mode
MOVE.B ascVolControl(A2),-(SP) ; save the external sound volume control
MOVE.B ascPlayRecA(A2),-(SP) ; save channel A play/record register
MOVE.B bmIntControlA(A2),-(SP) ; save sound input control register a
MOVE.B bmIntControlB(A2),-(SP) ; save sound input control register b
MOVE.B wSndControl(A2),-(SP) ; save sound control regiser
MOVE.L wSndFIFOBase(A2),-(SP) ; save sound FIF0 Base address
MOVE.L wSndSingerCtl1(A2),-(SP) ; save Singer Control Register 1 & 2
MOVE.B WhitneyPwrCtl,-(SP) ; save Power Control Register
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to Restore the Whitney registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreWhitney
MOVE.B (SP)+,WhitneyPwrCtl ; restore Power Control Register
MOVEA.L ASCBase,A2 ; point to the base of the ASC/Batman
MOVE.L (SP)+,wSndSingerCtl1(A2) ; restore Singer Control Register 1 & 2
MOVE.L (SP)+,wSndFIFOBase(A2) ; restore sound FIF0 Base address
MOVE.B (SP)+,wSndControl(A2) ; restore sound control regiser
MOVE.B (SP)+,bmIntControlB(A2) ; restore sound input control register b
MOVE.B (SP)+,bmIntControlA(A2) ; restore sound input control register a
MOVE.B (SP)+,ascPlayRecA(A2) ; restore channel A play/record register
MOVE.B (SP)+,ascVolControl(A2) ; restore the external sound volume control
MOVE.B (SP)+,ascMode(A2) ; restore the chip mode <K15>
JMP (A1) ; and return
;———————————————————————————————————————————————————————————————————————————————————————— <K10>
; Routine: BlackbirdModemType
;
; Input:
;
; Outputs: d0.l has the modem Type
;
; Trashes: d0
;
; Function: Returns type of modem installed in TIM Modem
;
;————————————————————————————————————————————————————————————————————————————————————————
BlackbirdModemType
move d0, d0 ; do something stupid for now so I can test this
rts
;_______________________________________________________________________________________ <K12>
; PrattPortAOn -- turns on serial port A
;
; Inputs:
; Outputs:
; Trashes:
; Notes: No need to do A -> C mapping. No need to Port B check (we don't have one).
;_______________________________________________________________________________________
PrattPortAOn
bset.b #SerPortAPwr,\
([PMgrBase],PmgrFlags2) ; log power state
bclr.b #WhitneySCCpwr,WhitneyPwrCtl ; turn on SCC driver chip
bclr.b #WhitneySCCclk,WhitneyPwrCtl ; start clock to SCC
rts
;_______________________________________________________________________________________ <K12> <K23>
; PrattPortAOff -- turns off serial port A
;
; Inputs:
; Outputs:
; Trashes:
;
; Notes: No need to do A -> C mapping. No need to Port B check (we don't have one).
; Disable interrupts so we don't get any by mistake on wake.
;_______________________________________________________________________________________
PrattPortAOff
bclr.b #SerPortAPwr,\
([PMgrBase],PmgrFlags2) ; log power state
move.l SCCRd, a0 ; Point to SCC
move.l SCCWr, a1
addq.l #2, a0 ; point to port A
addq.l #2, a1
move.b (a0), d0 ; sync up
move.b #9,(a1) ; write register 9
move.b #2,(a1) ; disable all SCC interrupts
bset.b #WhitneySCCpwr,WhitneyPwrCtl ; turn off SCC driver chip
bset.b #WhitneySCCclk,WhitneyPwrCtl ; stop clock to SCC
rts
;_______________________________________________________________________________________ <K12>
; PrattSonicOn -- turns on Sonic ethernet power
;
; Inputs:
; Outputs:
; Trashes: d2
;
;_______________________________________________________________________________________
PrattSonicOn
bset.b #EnetPwr,\
([PMgrBase],PmgrFlags3) ; log power state
bclr.b #WhitneyEnetPwr,WhitneyPwrCtl ; turn on power to Sonic
; wait for crystal to stabilize
move.w TimeVIAdb,d2 ; 1 ms delay
lsl.w #6,d2 ; 64 ms delay
@loop tst.b ([VIA])
dbra d2,@loop
bset.b #WhitneyEnetReset,WhitneyPwrCtl ; deassert _sleep pin <K17>
rts
;_______________________________________________________________________________________ <K12>
; PrattSonicOff -- turns off Sonic ethernet power
;
; Inputs:
; Outputs:
; Trashes:
;
;_______________________________________________________________________________________
PrattSonicOff
bclr.b #EnetPwr,\
([PMgrBase],PmgrFlags3) ; log power state
bclr.b #WhitneyEnetReset, WhitneyPwrCtl ; assert _sleep pin
bset.b #WhitneyEnetPwr,WhitneyPwrCtl ; turn off power to Sonic
rts
;_______________________________________________________________________________________ <K17>
; IsDriverInstalled -- looks to see if given driver is installed in the unit table
;
; Inputs: a0.l points to input driver name
; d1.l is the input driver name length
; Outputs: CCR has Z=0 for found, Z=1 for not found
; d0 = pointer to the DCE
; Trashes: d0
; Called by: Sleep Table code in Power Mgr
; Calls: .ENET driver _Open and _Control
;
;_______________________________________________________________________________________
IsDriverInstalled
@workregs REG a0-a3/d1-d4
movem.l @workregs, -(sp) ; save our working regs
MOVE.L UTableBase, A3 ; get address of the unit I/O table
MOVE.W UnitNtryCnt, D2 ; number of units to check
@CkInstLoop
MOVE.L (A3)+,D0 ; get next Device Control Entry handle
BEQ.S @nextEntry ; branch if no entry installed
MOVE.L D0,A2 ; DCE handle
MOVE.L (A2),D0 ; dereference handle
BEQ.S @nextEntry ; branch if null
MOVE.L D0,A1 ; A1 -> Device Control Entry
move.l d0, d4 ; save a pointer to the DCE
BTST #DRAMBased,DCtlFlags+1(A1) ; ROM-based?
MOVE.L DCtlDriver(A1), A1 ; driver ptr/handle
BEQ.S @1 ; br if ROM-based (A1 is a pointer)
MOVE.L A1, D0 ; be clean and check for 0 handle
BEQ.S @nextEntry ; skip if so
MOVE.L (A1), A1 ; deref handle
@1 MOVE.L A1, D0 ; is driver ptr nil?
BEQ.S @nextEntry ; br if so
LEA DrvrName(A1),A1 ; point A1 to driver name
MOVE.L D1, D0 ;
SWAP D0
MOVE.B (A1)+, D0 ; string 2 length
CMP.B D0, D1 ; are lengths the same?
BNE.S @nextEntry ; br if not (names shouldn't match if not)
_CmpString
BEQ @found ; found the driver!
@nextEntry SUBQ.W #1,D2 ; next unit table entry
BGT.S @CkInstLoop ; continue searching through all drivers
@found move.l d4, d0 ; return pointer to the DCE
bra.s @out ;
@notfound moveq #0, d0 ; driver not found
@out movem.l (sp)+, @workregs ; restore our working regs
rts
;_______________________________________________________________________________________ <K17>
; IsDriverOpen -- looks at driver flags in DCE to see if driver is open
;
; Inputs: d0 points to driver
; Outputs: CCR has Z=0 for open, Z=1 for not open
; d0 = pointer to the DCE
; Trashes: d0
; Called by: Sleep Table code in Power Mgr
; Calls: .ENET driver _Open and _Control
;
;_______________________________________________________________________________________
IsDriverOpen
@workregs REG a0-a3/d1-d4
movem.l @workregs, -(sp) ; save our working regs
movea.l d0, a0 ; point to the driver
move.w dCtlFlags(a0), d0 ; get driver flags
btst #5, d0 ; is the driver Open?
beq.s @notopen ; nope
@open moveq #1, d0 ; driver open
bra.s @out
@notopen moveq #0, d0 ; driver not open
@out movem.l (sp)+, @workregs ; restore our working regs
rts
;_______________________________________________________________________________________ <K17>
; EnetSleep/EnetWake -- Calls .ENET driver to sleep or wake SONIC
;
; Inputs: a1 points to return address
; Outputs: none
; Trashes: none
; Called by: Sleep Table code in Power Mgr
; Calls: .ENET driver _Open and _Control
;
;_______________________________________________________________________________________
ESleep EQU 254 ; Sleep the SONIC
EWake EQU 255 ; Wake the SONIC
EDetachPH EQU 248 ; Detach the protocol handler
EnetSleep
move.l #ESleep, d0 ; We're sleeping now
bra.s EnetWakeSleep
EnetWake
move.l #Ewake, d0 ; We're waking now
EnetWakeSleep
@workregs REG a0-a2/d1-d2
MOVEM.L @workregs,-(SP) ; save some reg's
move.l d0, d2 ; save our request
TestFor SONICExists ; do we have a SONIC?
beq.s @out ; no SONIC
lea EnetName, a0 ; point to driver name
moveq.l #0,d1
move.b (a0)+, d1 ; get the driver name length
bsr.w IsDriverInstalled ; is the .ENET driver installed?
beq.s @out ; driver not installed
bsr.w IsDriverOpen ; is the .ENET driver open?
beq.s @out ; driver not open
moveq #ioQElSize, d0 ; size the io stack frame
sub.w d0,sp ; Allocate IO stack frame
asr.w #1, d0 ; number of words in frame
subi.w #1, d0 ; our friend dbra
move.l sp, a2 ; point to start of frame
@clr clr.w (a2)+ ; clear frame
dbra d0, @clr
MOVE.L SP,A0 ; Save this place
LEA EnetName,A2 ; Get Ethernet refnum
MOVE.L A2,ioVNPtr(A0)
MOVE.B #fsCurPerm,ioPermssn(A0)
_Open
MOVE.w d2,csCode(A0) ; Sleep/Wake the Sonic
_Control ; (synchronously)
; MOVE #EDetachPH,CSCode(A0); Set code for detach PH
; MOVE #0,EProtType(A0) ; Set for 802.2
; _Control ; (synchronously)
add.w #ioQElSize,SP ; Allocate IO stack frame
@out movem.l (sp)+, @workregs ; restore the registers
JMP (A1) ; and return
EnetName dc.b 5 ; length of '.ENET'
dc.b '.ENET' ; driver name
;••••••••••••••••••••••••••••••••••••• Dispatch Tables ••••••••••••••••••••••••••••••••••••••••
IMPORT BasePRAM;••
IMPORT CPUSpeed;••
IMPORT ExternaVideoOnproc;••
IMPORT IdleDelay;••
IMPORT IdleDisable;••
IMPORT IdleEnable;••
IMPORT IdleMind
IMPORT IdleRead
IMPORT IdleState
IMPORT IdleUpdate;••
IMPORT IdleUpdateTrap;••
IMPORT ModemStatusRT ;••
IMPORT ModemTypeProc ;••
IMPORT PmgrTrap
IMPORT PowerMgrHook
IMPORT PDimScreens
IMPORT ScaledBattery
IMPORT ScsiDiskModeproc;••
IMPORT SecondaryInitproc
IMPORT SerialPower;••
ALIGN 4
DC.L PrimsTypePtr ; flags
DC.L (PwrDispatchEnd-PwrDispatchVects) ; number of table entries
PwrDispatchVects
DC.L PmgrTrap-PwrDispatchVects ; Selector #0
DC.L IdleUpdate-PwrDispatchVects ; Selector #1
DC.L IdleDelay-PwrDispatchVects ; Selector #2
DC.L IdleMind-PwrDispatchVects ; Selector #3
DC.L IdleRead-PwrDispatchVects ; Selector #4
DC.L IdleEnable-PwrDispatchVects ; Selector #5
DC.L IdleDisable-PwrDispatchVects ; Selector #6
DC.L CPUSpeed-PwrDispatchVects ; Selector #7
DC.L BasePRAM-PwrDispatchVects ; Selector #8
DC.L ScaledBattery-PwrDispatchVects ; Selector #9
DC.L PowerMgrHook-PwrDispatchVects ; Selector #10
DC.L PDimScreens-PwrDispatchVects ; Selector #11
DC.L 0 ; Selector #12 (FactoryDisp patched on disk)
DC.L PrivateFeatures-PwrDispatchVects ; Selector #13
PwrDispatchEnd
DC.L PrimsTypePtr ; flags
DC.L (PMgrHookEnd-PMgrHookVects) ; number of table entries
PMgrHookVects
DC.L SecondaryInitproc-PMgrHookVects ; Selector #0
DC.L ScsiDiskModeproc-PMgrHookVects ; Selector #1
DC.L ExternaVideoOnproc-PMgrHookVects ; Selector #2
DC.L ModemTypeProc-PMgrHookVects ; Selector #3
PMgrHookEnd
DC.L PrimsTypePtr ; flags
DC.L (PMgrOpTblEnd-PMgrOpTbl) ; number of table entries
PMgrOpTbl
DC.L PmgrTrap-PMgrOpTbl ; Pmgr Trap #A085
DC.L IdleUpdateTrap-PMgrOpTbl ; Pmgr Trap #A285
DC.L IdleState-PMgrOpTbl ; Pmgr Trap #A485
DC.L SerialPower-PMgrOpTbl ; Pmgr Trap #A685
PMgrOpTblEnd
;••••••••••••••••••••••••••••••••••••••• Sound VBL •••••••••••••••••••••••••••••••••••••••
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SndWatch
;
; Inputs: A0 - pointer to VBL task queue element
;
; Outputs: none
;
; Trashes: D0-D1, A0
;
; Function: A VBL task called once every ten seconds that checks the sound latch for
; ASC new use. If so then sound power is turned on. If power is already on
; then then the latch is cleared. If the latch stays clear for two VBLs then
; sound power is turned off.
;————————————————————————————————————————————————————————————————————————————————————————
SndWatch ;MOVE.L PmgrBase,A2
;LEA SwVBLTask(A2),A0 ; Get pointer to vbl task
MOVE.W #SndWFreq,vblCount(A0) ; reset the counter
CLR.W -(SP) ; allocate a buffer on the stack
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #SoundRead,-(SP) ; pmCommand = get sound latch state
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVE.B (SP)+,D0 ; get the sound state
BEQ.S @NoSound ; -> no sound activity
MOVEQ #sndOnclrLtch,D1 ; assume the latch is set (turn sound on, clear latch)
BTST #1,D0 ; is the latch set?
BNE.S @SndActive ; -> yes
MOVEA.L PMgrBase,A0 ; no, sound's been on but now it's not
TST.B SysTaskFlag(A0) ; are the sound input primitives set up?
BEQ.S @NoInputs ; -> no, there can't be a sound input source selected
jsrTBL sndInputSource ; is a sound source selected?
TST.B D0
BNE.S @NoSound ; -> yes, sound input is active so don't power off sound
@NoInputs MOVEQ #soundOff,D1 ; nothing's on so turn sound off
@SndActive MOVE.B D1,-(SP) ; put the new sound state into a buffer
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
MOVE.W #1,-(SP) ; pmLength = 1
MOVE.W #SoundSet,-(SP) ; pmCommand = set sound state
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4+2(SP),SP ; toss the parameter block and buffer
TST.B D1 ; is sound turned off?
BEQ.S @NoSound ; -> yes
_IdleUpdateDispatch
@NoSound RTS ; all done
;••••••••••••••••••••••••••••••••••••••• IdleMind ••••••••••••••••••••••••••••••••••••••••
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: RunIdleRoutinesProc (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: none
;
; Trashes: D0-D2, A0 (must preserve A1)
;
; Function: Runs IdleMind routines which are not based on LastAct. These routines
; have priority over the LastAct based ones with the exception of the
; countdown timers.
;————————————————————————————————————————————————————————————————————————————————————————
RunIdleRoutinesProc
BSR.S ChkDimming ; is it time to Power Down the Screen
BSR.S ChkHdSpinDown ; Is it time to Power Down the HD
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: ChkDimming
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: none
;
; Trashes: D0-D2, A0 (must preserve A1)
;
; Function: Runs IdleMind routines which are not based on LastAct. These routines
; have priority over the LastAct based ones with the exception of the
; countdown timers.
;————————————————————————————————————————————————————————————————————————————————————————
ChkDimming
TST.B DimmingDisable(A2) ; IF counting semaphor = 0 THEN
BNE.S @Exit ;
BSR CurFrontProcEqual ; IF Process are the same THEN
BEQ.S @Exit ;
MOVE.L Ticks,D0 ; D0 = Current time
SUB.L LastUsrAct(A2),D0 ; Calc elapsed time since last user activity
BMI.S @hadActivityNoDim ; IF LastUsrAct > Tick THEN exit
MOVEQ #0,D1 ; Clear register
CMP.L DimmingWaitTime(A2),D0 ; IF TimeToWait <= TimeSinceLastAct THEN
BLO.S @hadActivityNoDim ;
BSET #PmgrDimStatus,PmgrFlags2(A2) ; Set the flag that we are dimmed
BNE.S @Exit ; IF not already dimmed THEN
MOVEQ #1,D0 ; Set Video for Power Down
BRA VidLowPwrSelect ; Set Video State
@hadActivityNoDim ; ELSE
BCLR #PmgrDimStatus,PmgrFlags2(A2) ; Clear the flag that we are dimmed
BEQ.S @Exit ; IF dimmed THEN
MOVEQ #0,D0 ; Set Video for Power Up
BRA VidLowPwrSelect ; Set Video State
@Exit ; ENDIF
RTS ; ENDIF
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CheckCountDownTimer (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: CCR - BEQ = not in countdown mode, BNE = go to sleep
;
; Trashes: D0
;
; Function: returns whether or not we're in a countdown condition
;————————————————————————————————————————————————————————————————————————————————————————
CheckCountDownTimer
CMP.B #4,LastLevel(A2) ; Test for level 4 sleep
BNE.S @NotCountingDown ; IF LastLevel != 4 THEN exit
CMP.B #SleepWait,Level4Cnt(A2) ; Test for standing 10 count
BLS.S @NotCountingDown ; IF Level4Cnt != 10 THEN exit
BSET #LowPowerSleep,PMgrFlags2(A2) ; set the low power sleep flag <H27>
MOVEQ #-1,D0 ; Set to force sleep
RTS ; Goodnight
@NotCountingDown
MOVEQ #0,D0 ; Set condition codes
RTS ; exit
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: ChkHdSpinDown (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: none
;
; Trashes: D0-D2, A0 (must preserve A1)
;
; Function: determines whether to spin down the hard drive. If so, then jumps through
; a vector to spin down the hard drive
;————————————————————————————————————————————————————————————————————————————————————————
ChkHdSpinDown
MOVE.L LastHd(A2),D2 ; Get last HD activity
BEQ.S @Done ; IF DriveSpunDown THEN exit
MOVE.L HDvector(A2),D0 ; IF HDvector = null THEN <H15>
BEQ.S @Done ; exit
BTST #dockingStation,dockFlags(A2) ; are we in a docking station? <H15>
BNE.S @Done ; -> yes, never spin down the hard disk <H15>
BTST.B #HasCharger,Charger(A2) ; Check for Battery
BEQ.S @OnBattery ; IF !HasCharger THEN On Battery
BTST.B #ChargeSleep,SleepFlags(A2) ; Check if in ChargeSleep since no spin down while charging
BNE.S @Done ; IF ChargeSleep THEN exit
@OnBattery MOVEA.L D0,A0 ; get the spin down routine vector <H15>
MOVEQ #0,D0
MOVE.B HDTime(A2),D0 ; Get current HD timeout
BNE.S @hdTOok ; IF HDTime = null THEN
MOVE.B #DfltHDTime,D0 ; Set Default
@hdTOok MULU.W #pram2ticks,D0 ; Convert HD time out to ticks
MOVE.L Ticks,D1 ; Get current time
SUB.L D2,D1 ; D1 = elapsed time since last HD activity
CMP.L D1,D0 ; Check for HD timeout
BGT.S @Done ; IF elapsedTime > TimeOut THEN
JSR (A0) ; Call spin down routine
@Done RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: ChkSleepTimeOut (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: CCR - BEQ = continue, BNE = request sleep
;
; Trashes: D0
;
; Function: returns whether to issue a sleep request
;————————————————————————————————————————————————————————————————————————————————————————
ChkSleepTimeOut
BTST.B #HasCharger,Charger(A2) ; Check for Battery
BEQ.S @OnBattery ; IF !HasCharger THEN On Battery
BTST.B #ChargeSleep,SleepFlags(A2) ; Check if in ChargeSleep since no spin down while charging
BNE.S @Done ; IF ChargeSleep THEN exit
@OnBattery MOVEQ #0,D0
MOVE.B SleepTime(A2),D0 ; Get current Sleep timeout
BNE.S @slpTOok ; IF SleepTime = null THEN
MOVE.B #DfltSlpTime,D0 ; Set Default
@slpTOok MULU.W #pram2ticks,D0 ; Convert Sleep timeout to ticks
ADD.L LastAct(A2),D0 ; Calc time to go to sleep
CMP.L Ticks,D0 ; IF TimeToSleep >= CurrentTime THEN
BGE.S @Done ; exit
TST.B AutoSlpDisable(A2) ; IF counting semaphor > 0 THEN
BGT.S @Done ; exit
BSR CurFrontProcEqual ; IF Processes <> THEN
BEQ.S @Done ; exit
MOVEQ #-1,D0 ; Set a sleep request
RTS ; Try to Sleep
@Done MOVEQ #0,D0 ; Set condition codes
RTS ; Return
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: ChkIdle (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: CCR - BEQ = continue, BNE = go idle
;
; Trashes: D0-D1
;
; Function: determines whether or not we're in idle
;————————————————————————————————————————————————————————————————————————————————————————
ChkIdle
BTST #dockNoPowerCycle,dockFlags(A2) ; is power cycling allowed? <H5>
BNE.S @hadActivity ; -> no, bail <H5>
TST.B MBState ; IF mouse down THEN
BEQ.S @UpdateOut ; Update Activity and Exit
TST.B watchCrsr(A2) ; IF watchCrsr THEN
BNE.S @UpdateOut ; Update Activity and Exit
BTST.B #IdleBit,SleepFlags(A2) ; IF idleDisable THEN
BNE.S @hadActivity ; Exit and set Activity
TST.B IdleFlagCnt(A2) ; IF IdleFlagCnt THEN
BGT.S @hadActivity ; Exit and set Activity
MOVE.L Ticks,D0 ; Mouse activity woke us up
SUB.L LastAct(A2),D0 ; Calc elapsed time since last activity
BMI.S @hadActivity ; IF LastAct > Tick THEN exit
MOVEQ #0,D1 ; Clear register
MOVE.W PwrCycWaitTime(A2),D1 ; Get the time to wait
CMP.L D0,D1 ; IF TimeToWait >= TimeSinceLastAct THEN
BGE.S @hadActivity ; Exit
@noActivity
MOVEQ #-1,D0 ; Set condition codes
RTS
@UpdateOut
MOVE.L Ticks,LastAct(A2) ; Update activity
@hadActivity
MOVEQ #0,D0 ; Set condition codes
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CalcProgressive (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: D1 - power cycling count
;
; Trashes: D0
;
; Function: calculates the number of power cycles we will follow through
;————————————————————————————————————————————————————————————————————————————————————————
CalcProgressive
MOVE.W PwrCycCounter(A2),D1 ; Power cycle a limited number of times
MOVE.L LastAct(A2),D0 ; D0 = LastAct
CMP.L PMgrScratch.ProgLastAct(A2),D0 ; Check for no activity
BNE.S @SomeAct ; Some Activity. Branch.
MOVE.W PMgrScratch.ProgCounter(A2),D1 ; Get current power cycle counter
ADD.W PwrCycProgGrow(A2),D1 ; Increment counter
CMP.W PwrCycProgMax(A2),D1 ; Set power cycle number to new value
BHS.S @SetMax ; Have we reached maximum value
MOVE.W D1,PMgrScratch.ProgCounter(A2) ; Save it for next time
RTS
@SetMax MOVE.W PwrCycProgMax(A2),D1 ; Set power cycling count to maximum level
RTS
@SomeAct MOVE.L D0,PMgrScratch.ProgLastAct(A2) ; Reset Activity for next check
MOVE.W D1,PMgrScratch.ProgCounter(A2) ; Reset counter
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: GoPowerCycle (IdleMind)
;
; Inputs: A2 - pointer to Power Manager variables
;
; Outputs: CCR - BEQ = continue, BNE = go idle
;
; Trashes: D0-D1
;
; Function: high-level power cycling call
;————————————————————————————————————————————————————————————————————————————————————————
GoPowerCycle
BSR.L SetSupervisorMode ; Set the machine to supervisor mode
MOVE.W D0,SaveCPUState.CPUSRsave(A2) ; Save the the SR
MOVE.L AutoInt7,SaveCPUState.CPUNMIsave(A2); Save the NMI Vector
MOVE.L ResetSP,-(SP) ; save current ResetSP
MOVE.L ResetPC,-(SP) ; save current ResetPC
BTST.B #hwCbFPU,HWCfgFlags ; Do we have an FPU?
BEQ.S @docycle ; IF hasFPU THEN
FMOVEM.L FPCR/FPSR/FPIAR,-(SP) ; Save them regs
FMOVEM.X FP0-FP7,-(SP) ; Save more them regs
@docycle MOVE.L LastAct(A2),-(SP) ; Save lastact as an activity flag
MOVE.L PwrCycProc(A2),A0 ; Get pointer to power cycling routine
JSR (A0) ; Go power cycle
MOVE.L (SP)+,D0 ; Get the previous lastact
CMP.L LastAct(A2),D0 ; Test for any activity
DBNE D1,@docycle ; Go through another loop if none
BTST.B #hwCbFPU,HWCfgFlags ; Do we have an FPU?
BEQ.S @noFPU ; IF hasFPU THEN
FMOVEM.X (SP)+,FP0-FP7 ; Restore more them regs
FMOVEM.L (SP)+,FPCR/FPSR/FPIAR ; Restore them regs
@noFPU MOVE.L (SP)+,ResetPC ; Restore the ResetPC
MOVE.L (SP)+,ResetSP ; Restore the ResetSP
MOVE.W SaveCPUState.CPUSRsave(A2),SR ; Restore the Status Register from power cycle
MOVE.L SaveCPUState.CPUNMIsave(A2),AutoInt7; Restore the NMI Vector
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: CurFrontProcEqual
;
; Inputs: none
;
; Outputs: CCR - BEQ = Processes Not Equal, BNE = Processes Equal
;
; Trashes: D0
;
; Function: returns whether the process managers front and current process are the same.
; This is important since we can neither sleep nor dim if they are different.
;————————————————————————————————————————————————————————————————————————————————————————
CurFrontEqFrame RECORD 0,DECR
FrontSerialNum DS.B ProcessSerialNumber
CurSerialNum DS.B ProcessSerialNumber
Result DS.W 1
CurFrontEqFrameSz EQU *
ENDR
CurFrontProcEqual
CurFrontProcRegs REG A0-A1
WITH CurFrontEqFrame
LINK A6,#CurFrontEqFrameSz ; Build StackFrame
MOVEM.L CurFrontProcRegs,-(SP) ; Save them regs
SUBQ.W #2,SP ; Make space for OSErr
PEA CurSerialNum(A6) ; Set pointer to CurSerialNum
_GetCurrentProcess ; Get Process Managers Current Process
PEA FrontSerialNum(A6) ; Set pointer to FrontSerialNum
_GetFrontProcess ; Get Process Managers Front Process
TST.W (SP) ; IF Error THEN
BNE.S @ProcessEqual ; NoFrontProcesses Exit, Assume ProcessEqual
PEA CurSerialNum(A6) ; Set pointer to CurSerialNum
PEA FrontSerialNum(A6) ; Set pointer to FrontSerialNum
PEA Result(A6) ; Set pointer to result
_SameProcess ; IF CurrentProcess = FrontProcess THEN
TST.W (SP) ; IF Err THEN
BNE.S @ProcessNotEqual ; ProcessNotEqual
TST.B Result(A6) ; ELSE
BEQ.S @ProcessNotEqual ; ProcessEqual
@ProcessEqual
MOVEQ #1,D0 ; Set condition codes for Processes Equal
BRA.S @Exit ; That's all folks
@ProcessNotEqual
MOVEQ #0,D0 ; Set condition codes for no sleep
@Exit
ADDQ.W #2,SP ; Clean up the stack
MOVEM.L (SP)+,CurFrontProcRegs ; Restore them regs
UNLK A6 ; Release stack fram
TST.L D0 ; Set Condition codes
RTS ; <5>
;••••••••••••••••••••••••••••••••••••••• PowerCycling •••••••••••••••••••••••••••••••••••••••
;————————————————————————————————————————————————————————————————————————————————————————
;
; PowerCycle
;
;————————————————————————————————————————————————————————————————————————————————————————
PowerCycleRegs REG D0-D7/A0-A6
WITH CPUStateRec
;———————————————————————————————————————————————————————————————————————
MACHINE MC68040
PowerCycle040
@SaveSetRegs REG D0-D7/A3-A6
MOVE.W SR,-(SP) ; Save status register
ORI.W #HiIntMask,SR ; No more interrupts
MOVEM.L PowerCycleRegs,-(SP) ; save them registers
MOVE.L PMgrBase,A2 ; get pointer to globals
LEA SaveCPUState(A2),A1 ; get pointer to SaveCPUState area
MOVEC CACR,D7 ; get current Cache Register
MOVEQ #0,D0 ; clear register
MOVEC D0,CACR ; disable caches
CPUSHA bc ; flush both caches entirely
; Get CPU Internal State Registers
MOVEC URP,D0 ; Save User Root Pointer
MOVEC SRP,D1 ; Save Supervisor Root Pointer
MOVEC TC,D2 ; Save TC
MOVEC DTT0,D3 ; Save Data TT0
MOVEC DTT1,D4 ; Save Data TT1
MOVEC ITT0,D5 ; Save Instruction TT0
MOVEC ITT1,D6 ; Save Instruction TT1
MOVEC VBR,A3 ; Save vector base reg
MOVE.L AutoInt7(A3),-(SP) ; Save the NMI Vector
MOVEC USP,A4 ; Save User Stack Pointer
MOVEC MSP,A5 ; Save Master Stack Pointer
MOVEC ISP,A6 ; Save Interrupt Stack Pointer
MOVEM.L @SaveSetRegs,(A1) ; Save all them special regs
; Last Chance for SCC
MOVEQ #(1<<SerPortAPwr)+\
(1<<SerPortBPwr),D1 ; IF SCC_Pwr THEN
AND.B PmgrFlags2(A2),D1 ; SCC may have data
BEQ.S @NoSCC ; ELSE branch
BTST #0,([SccRd]) ; IF SCC has Data THEN
BNE.S @DontCycle ; Don't kill the power
@NoSCC
MOVE.L PwrCycRestore(A2),\
AutoInt7(A3) ; Set NMIVec to our PwrCycling NMI handler
MOVE.L PwrCycRestore(A2),\
ResetPC ; Set the PC to restore code when coming up
MOVE.L A1,ResetSP ; Save it in ResetSP for powering up
; Kill Power
MOVE.L PowerCycleReg(A2),A0 ; Get pointer to Pratt Nap mode register
MOVE.B PwrCycRegValue(A2),(A0) ; set the magic value <K22>
BRA.S * ; Wait for the drugs to take effect
@DontCycle
MOVEC D0,CACR ; restore them caches
ADDQ.W #4,SP ; clear the NMI from the stack
MOVEM.L (SP)+,PowerCycleRegs ; Restore them regs
MOVE.W (SP)+,SR
RTS
;————————————————————————————————————————————————————————————————————————————————————————
MACHINE MC68030
PowerCycle030
MOVE.W SR,-(SP)
OR.W #HiIntMask,SR ; No more interrupts
MOVEM.L PowerCycleRegs,-(SP) ; save all for now, Save only the important registers
MOVEC CACR,D0 ; Now save cache regs
OR.W #(1<<11)+(1<<3),D0 ; Flush caches upon return
MOVEC CAAR,D1 ;
MOVEC VBR,A0 ; Also save vector base
MOVE.L USP,A1 ; and alternats stack pointers
MOVEC MSP,A2 ; .
MOVEM.L D0/D1/A0-A2,-(SP) ; Save some cool registers
MOVEQ #0,D0
MOVEC D0,VBR ; need to put return addr right at the start
MOVE.L PmgrBase,A1 ; get pmgr locals
MOVEA.L PowerCycleReg(A1),A2 ; Get powercycling register in A2 <H29>
MOVE.L PwrCycRestore(A1),ResetPC; Set the PC to restore code when coming up
MOVE.L SP,SaveCPUState.CPUISPsave(A1) ; save old SP
PMOVE TC,SaveCPUState.CPUMMUTCsave(A1); Save TC
PMOVE CRP,SaveCPUState.CPUMMUCRPsave(A1) ; Save CRP
PMOVE TT1,SaveCPUState.CPUMMUTT1save(A1) ; Save TT1
PMOVE TT0,SaveCPUState.CPUMMUTT0save(A1) ; Save TT2
MOVE.L PmgrVarPhysPtr(A1),A3 ; Get the physical address of the PMgr Globasl <25> HJR
LEA SaveCPUState(A3),A3 ; PwrCycGlobals-4 Byte below must be free for NMIStkFrm <25> HJR
MOVE.L A3,ResetSP ; Save it in ResetSP for powering up <25> HJR
MOVE.L PwrCycRestore(A1),AutoInt7 ; Set NMIVec to our PwrCycling NMI handler <24> HJR
MOVE.L SccRd,A3 ; SCC may have data to get
BTST #0,(A3) ; Is there any SCC Data
BNE.S @DontCycle ; Yes.. Forget killing the power
MOVE.L D0,([RomBase]) ; Clear the Bus. Yes I Know it's in ROM... <6> HJR
MOVE.L D0,(A2) ; Pull the pin <6> HJR
BRA.S * ; Wait for the drugs to take effect
@DontCycle MOVEC A0,VBR ; Restore the VBR <37> HJR
MOVE.L SaveCPUState.\
CPUNMIsave(A1),AutoInt7 ; Restore the NMI Vector <33> HJR
ADDA.L #5*4,SP ; Restore stack state
MOVEM.L (SP)+,PowerCycleRegs ; Restore them regs
MOVE.W (SP)+,SR
RTS
;———————————————————————————————————————————————————————————————————————
PowerCycle020
MOVE.W SR,-(SP)
OR.W #HiIntMask,SR ; No more interrupts
MOVEM.L PowerCycleRegs,-(SP) ; save all for now, Save only the important registers
MOVEC CACR,D0 ; Now save cache regs
OR.W #(1<<11)+(1<<3),D0 ; Flush caches upon return
MOVEC CAAR,D1 ;
MOVEC VBR,A0 ; Also save vector base
MOVE.L USP,A1 ; and alternats stack pointers
MOVEC MSP,A2 ; .
MOVEM.L D0/D1/A0-A2,-(SP) ; Save some cool registers
MOVEQ #0,D0
MOVEC D0,VBR ; need to put return addr right at the start
MOVE.L PmgrBase,A1 ; get pmgr locals
MOVEA.L PowerCycleReg(A1),A2 ; Get powercycling register in A1 <H29>
MOVE.L PwrCycRestore(A1),ResetPC; Set the PC to restore code when coming up
MOVE.L SP,ResetSP ; Save the stack pointer in ResetSP for power up
MOVE.L PwrCycRestore(A1),AutoInt7; Set NMIVec to our PwrCycling NMI handler <24> HJR
MOVE.L SccRd,A3 ; SCC may have data to get
BTST #0,(A3) ; Is there any SCC Data
BNE.S @DontCycle ; Yes.. Forget killing the power
MOVE.L D0,([RomBase]) ; Clear the Bus. Yes I Know it's in ROM... <6> HJR
MOVE.L D0,(A2) ; Pull the pin <6> HJR
BRA.S * ; Wait for the drugs to take effect
@DontCycle
MOVEC A0,VBR ; Restore the VBR <37> HJR
MOVE.L SaveCPUState.\
CPUNMIsave(A1),AutoInt7 ; Restore the NMI Vector <33> HJR
ADDA.L #5*4,SP ; Restore stack state
MOVEM.L (SP)+,PowerCycleRegs ; Restore them regs
MOVE.W (SP)+,SR
RTS
;———————————————————————————————————————————————————————————————————————
MACHINE MC68040
Restore040
@SaveSetRegs REG D0-D7/A3-A6
MOVEM.L (SP),@SaveSetRegs ; get some saved special regs
MOVEC D0,URP ; restore User Root Pointer
MOVEC D1,SRP ; restore Supervisor Root Pointer
MOVEC D3,DTT0 ; restore Data TT0
MOVEC D4,DTT1 ; restore Data TT1
MOVEC D5,ITT0 ; restore Instruction TT0
MOVEC D6,ITT1 ; restore Instruction TT1
MOVEC A3,VBR ; restore VBR
MOVEC A4,USP ; restore User Stack pointer
MOVEC A5,MSP ; restore Master Stack pointer
MOVEC A6,ISP ; restore Interrupt Stack pointer
PFLUSHA ; flush ATC
MOVEC D2,TC ; restore TC
CINVA BC ; invalidate both caches
MOVEC D7,CACR ; Restore Vital CPU registers
MOVE.L (SP)+,AutoInt7(A3) ; Restore the NMI Vector
MOVEM.L (SP)+,PowerCycleRegs ; Restore them regs
MOVE.W (SP)+,SR
RTS
;———————————————————————————————————————————————————————————————————————
MACHINE MC68030
Restore030
MOVE.L ResetSP,A0 ; Save the Power Manager globals in the stack <25> HJR
MOVE.L CPUISPsave(A0),SP ; Restore the stack to the previous life
PMOVE CPUMMUTT0save(A0),TT0 ; "Pop" the MMU regs of the video stack
PMOVE CPUMMUTT1save(A0),TT1
PMOVE CPUMMUCRPsave(A0),CRP
PMOVE CPUMMUTCsave(A0),TC ; MMU is now restored, we have memory
MOVEM.L (SP)+,D0/D1/A0-A2
MOVEC D0,CACR ; Restore Vital CPU registers
MOVEC D1,CAAR
MOVEC A0,VBR
MOVEC A1,USP
MOVEC A2,MSP
MOVE.L PMgrBase,A0 ; Get the Globals <24> HJR
MOVE.L SaveCPUState.\
CPUNMIsave(A0),AutoInt7 ; Restore the NMI Vector <24> HJR
MOVEM.L (SP)+,PowerCycleRegs ; Restore them regs
MOVE.W (SP)+,SR
RTS
;———————————————————————————————————————————————————————————————————————
Restore020
MOVEM.L (SP)+,D0/D1/A0-A2 ; restore cool registers
MOVEC D0,CACR ; Restore Vital CPU registers
MOVEC D1,CAAR
MOVEC A0,VBR
MOVE.L A1,USP
MOVEC A2,MSP
MOVE.L PMgrBase,A0 ; Get the Globals <25> HJR
MOVE.L SaveCPUState.\
CPUNMIsave(A0),AutoInt7 ; Restore the NMI Vector <25> HJR
MOVEM.L (SP)+,PowerCycleRegs ; Restore them regs
MOVE.W (SP)+,SR
RTS
ENDWITH
;•••••••••••••••••••••••••••••••••••••••• Sleep ••••••••••••••••••••••••••••••••••••••••••
;
; The following are a set of possible routines that are used to save the state, or
; set necessary conditions in order for the machine to sleep. For each machine there
; is a corresponding table of entries which point to the necessary routines. The
; register convention is that A0/A1 must be PRESERVED throughout all routines. All
; other register can be trashed and should not be relied upon.
;
;————————————————————————————————————————————————————————————————————————————————————————
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to power down hard drive (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SleepHD MOVEA.L PMgrBase,A2 ; get pointer to globals
BTST #HDPowerOn,PmgrFlags(A2); Clear the Hard Disk semaphor
BEQ.S @SkipHDSpinDown ; If set, spin down the hard disk
MOVE.L HDvector(A2),D0 ; Does the vector exist
BEQ.S @SkipHDSpinDown ; Nope... Go on
MOVEA.L D0,A2 ; Get vector to hard disk spin down task
JSR (A2) ; Spin down hard disk
@SkipHDSpinDown
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the VIA1 registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveVIA1 MOVEA.L VIA,A2
MOVE.B vBufB(A2),D0 ; load up all the VIA registers
MOVE.B vDIRB(A2),D1
MOVE.B vBufA(A2),D2
MOVE.B vDIRA(A2),D3
MOVE.B vIER(A2),D4
ORI.B #(1<<7),D4 ; set the Via Set bit so that value will stick
MOVE.B vACR(A2),D5
MOVE.B vPCR(A2),D6
MOVEM.W D0-D6,-(SP) ; save the VIA registers
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the VIA2 registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveVIA2 MOVEA.L VIA2,A2
MOVE.B vBufB(A2),D0 ; load up all the VIA registers
MOVE.B vDIRB(A2),D1
MOVE.B vBufA(A2),D2
MOVE.B vDIRA(A2),D3
MOVE.B vIER(A2),D4
ORI.B #(1<<7),D4 ; set the Via Set bit so that value will stick
MOVE.B vACR(A2),D5
MOVE.B vPCR(A2),D6
MOVEM.W D0-D6,-(SP) ; save the VIA registers
BCLR.B #v2CDis2,vBufB(A2) ; lower the cache disable line to save power
JMP (A1) ; and return
IF hasNiagra THEN
;————————————————————————————————————————————————————————————————————————————————————————
; Dartanian ASC/Batman save code (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveASCBatmanDart ;
MOVEA.L UnivInfoPtr,A2 ; point to the ProductInfo table,
ADDA.L DecoderInfoPtr(A2),A2 ; then to the DecoderInfo table,
MOVEA.L JAWSAddr(A2),A2 ; then to the Niagra base address,
ADDA.L #NiagraGUR+PontiSndCtl,A2 ; and finally to the sound register
;
BSET #PontiSndPWMOff,(A2) ; turn off power amps
ENDIF
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the ASC and Batman registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
batmanSnd EQU $B0 ; version number for Batman Chip
SaveASCBatman
MOVEA.L ASCBase,A2 ; point to the base of the ASC/Batman
MOVE.B ascMode(A2),-(SP) ; save the chip mode
MOVE.B ascVolControl(A2),-(SP) ; save the external sound volume control
MOVE.B $80A(A2),-(SP) ; save channel A play/record register
CMPI.B #batmanSnd,ascVersion(A2) ; is this a Batman?
BNE.S @NotBatman ; -> nope, that's all we save
MOVE.B ascTestReg(A2),-(SP) ; save test control register
MOVE.L A1,D2 ; save the return address
MOVEQ.L #0,D1 ; reg D1 = channel offset (0=A,$20=B)
@saveBatReg LEA $F09+1(A2),a1 ; save Batman channel control regs ($F00-$F09)
ADDA.L D1,a1 ; add channel offset for A or B
MOVEQ.L #10-1,D0 ;
@saveBatC MOVE.B -(a1),-(SP) ;
DBRA D0,@saveBatC ;
LEA $F17+1(A2),a1 ; save CDXA coefficient regs ($F10-$F17)
ADDA.L D1,a1 ; add channel offset for A or B
MOVEQ.L #8-1,D0 ;
@saveCDXA MOVE.B -(a1),-(SP) ;
DBRA D0,@saveCDXA ;
TST.L D1 ; channel A or B
BNE.S @BatmanDone ; already saved both channels A and B
MOVE.L #$20,D1 ; set channel offset to channel B
BRA.S @saveBatReg ; save channel B registers
@BatmanDone
MOVEA.L D2,A1 ; restore the return address
@NotBatman JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to poweroff Sound (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SoundPowerDown ;
MOVEA.L UnivInfoPtr,A2 ; point to the ProductInfo table,
ADDA.L DecoderInfoPtr(A2),A2 ; then to the DecoderInfo table,
MOVEA.L JAWSAddr(A2),A2 ; then to the Niagra base address,
ADDA.L #NiagraGUR+PontiSndCtl,A2 ; and finally to the sound register
;
BSET #PontiSndLatchClr,(A2) ; pulse (positive) latch clear bit
BCLR #PontiSndLatchClr,(A2) ;
;
BCLR #PontiSndPwrOn,(A2) ; turn off sound power
;
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the video registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveLCD Moveq #0,D1 ; Say were about to sleep.
Bsr SaveRestoreLCD ; Go save the world.
Jmp (A1) ; Vamoose.
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the FPU registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveFPU BTST #hwCbFPU,HWCfgFlags ; do we have an FPU?
BEQ.S @NoFPU ; -> no
FMOVEM.X FP0-FP7,-(SP) ; save general purpose registers
FMOVEM.L FPCR/FPSR/FPIAR,-(SP) ; save FPU condition registers
@NoFPU JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the 68040 registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveSlp040
@SaveSetRegs REG D0-D7/A3-A6
MACHINE MC68040
MOVEA.L PmgrBase,A2 ; get pointer to globals
MOVEC CACR,D7 ; get current Cache Register
MOVEQ #0,D0 ; clear register
MOVEC D0,CACR ; disable caches
CPUSHA BC ; flush both caches entirely
; Get CPU Internal State Registers
MOVEC URP,D0 ; Save User Root Pointer
MOVEC SRP,D1 ; Save Supervisor Root Pointer
MOVEC TC,D2 ; Save TC
MOVEC DTT0,D3 ; Save Data TT0
MOVEC DTT1,D4 ; Save Data TT1
MOVEC ITT0,D5 ; Save Instruction TT0
MOVEC ITT1,D6 ; Save Instruction TT1
MOVEC VBR,A3 ; Save vector base reg
MOVEC USP,A4 ; Save User Stack Pointer
MOVEC MSP,A5 ; Save Master Stack Pointer
MOVEC ISP,A6 ; Save Interrupt Stack Pointer
MOVEM.L @SaveSetRegs,SaveCPUState(A2) ; Save all them special regs
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to save the 68030 registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveSlp030
@SaveSetRegs REG D0-D5
MACHINE MC68030
MOVEA.L PmgrBase,A2 ; Get pointer to our globals
PMOVE CRP,SaveCPUState.CPUMMUCRPsave(A2); Save CRP
PMOVE TC,SaveCPUState.CPUMMUTCsave(A2) ; Save TC
PMOVE TT0,SaveCPUState.CPUMMUTT0save(A2); Save TT2
PMOVE TT1,SaveCPUState.CPUMMUTT1save(A2); Save TT1
MOVEC VBR,D0 ; Also save vector base
MOVEC USP,D1 ; and alternats stack pointers
MOVEC MSP,D2 ; .
MOVEC ISP,D3 ; and old sp
MOVEC CACR,D4 ; Now save cache regs
OR.W #(1<<11)+(1<<3),D4 ; Flush caches upon return
MOVEC CAAR,D5 ;
MOVEM.L @SaveSetRegs,\
SaveCPUState.CPUVBRsave(A2) ; Save some cool registers
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to setup state info before going to sleep (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
SaveSleepInfo
MOVEA.L PMgrBase,A2 ; Get pointer to our globals
MOVE.L #SleepConst,SleepSaveFlag(A2) ; set a flag that sleep has been entered
JMP (A1)
;————————————————————————————————————————————————————————————————————————————————————————
; _Sleep routine to send a sleep command to the PMGR (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
IF hasMSC THEN
SendSleepLP PEA 'BORG' ; low power sleep signature
BCLR #LowPowerSleep,PMgrFlags2(A2) ; are we sleeping because of a low power condition?
BNE.S HaveSig ; -> yes
ADDQ.W #4,SP ; no, toss the low power signature
ENDIF
SendSleep MOVE.L A0,-(SP) ; save this dam thing
PEA SleepSig ; put the sleep signature into a buffer
HaveSig MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
MOVE.W #4,-(SP) ; pmLength = 4
MOVE.W #SleepReq,-(SP) ; pmCommand = sleep…
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the sleep command
LEA pmRBuffer+4+4(SP),SP ; clean up the stack
MOVEA.L (SP)+,A0 ; restore it
JMP (A1) ; and return
;•••••••••••••••••••••••••••••••••••••••• Wakeup •••••••••••••••••••••••••••••••••••••••••
;
; The following are a set of possible routines that are used to restore the state, or
; set necessary conditions in order for the machine to wake from sleep. For each machine
; there is a corresponding table of entries which point to the necessary routines. The
; register convention is that A0/A1 must be PRESERVED throughout all routines. All
; other register can be trashed and should not be relied upon.
;
;————————————————————————————————————————————————————————————————————————————————————————
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the MMU registers for '040 (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreSlp040
@RestoreSetRegs REG D0-D7/A3-A6
MACHINE MC68040
MOVEA.L PmgrBase,A2 ; get pointer to our Globals
MOVEM.L SaveCPUState(A2),@RestoreSetRegs; get some saved special regs
MOVEC D0,URP ; restore User Root Pointer
MOVEC D1,SRP ; restore Supervisor Root Pointer
MOVEC D3,DTT0 ; restore Data TT0
MOVEC D4,DTT1 ; restore Data TT1
MOVEC D5,ITT0 ; restore Instruction TT0
MOVEC D6,ITT1 ; restore Instruction TT1
MOVEC A3,VBR ; restore VBR
MOVEC A4,USP ; restore User Stack pointer
MOVEC A5,MSP ; restore Master Stack pointer
MOVEC A6,ISP ; restore Interrupt Stack pointer
PFLUSHA ; flush ATC
MOVEC D2,TC ; restore TC
CINVA BC ; invalidate both caches
MOVEC D7,CACR ; Restore Vital CPU registers
MOVEQ #0,D7 ; Clear register for WakeRoutine to work
JMP (A1) ; return
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the MMU registers for '030 (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreSlp030
@RestoreSetRegs REG D0-D5
MACHINE MC68030
MOVEA.L PmgrBase,A2 ; get pointer to our Globals
MOVEM.L SaveCPUState.CPUVBRsave(A2),\
@RestoreSetRegs ; get some special registers
MOVEC D0,VBR ; restore the Vector Base Register
MOVEC D1,USP ; restore the User Stack Pointer
MOVEC D2,MSP ; restore the Master Stack Pointer
MOVEC D3,ISP ; restore the Interrupt Stack Pointer
PMOVE SaveCPUState.CPUMMUCRPsave(A2),\;
CRP ; restore CRP
PMOVE SaveCPUState.CPUMMUTT1save(A2),\;
TT1 ; restore TT1
PMOVE SaveCPUState.CPUMMUTT0save(A2),\;
TT0 ; restore TT2
PFLUSHA ; flush ATC
PMOVE SaveCPUState.CPUMMUTCsave(A2),\ ;
TC ; restore TC and turn on MMU
MOVEC D4,CACR ; restore the Cache register
MOVEC D5,CAAR ; restore the Cache Address register
JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the FPU registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreFPU
BTST #hwCbFPU,HWCfgFlags ; do we have an FPU?
BEQ.S @NoFPU ; -> no
FMOVEM.L (SP)+,FPCR/FPSR/FPIAR ; restore FPU condition registers
FMOVEM.X (SP)+,FP0-FP7 ; restore general purpose registers
@NoFPU JMP (A1) ; and return
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to save the video registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreLCD
MOVEQ #1,D1 ; Say were about to sleep.
BSR SaveRestoreLCD ; Go save the world.
JMP (A1) ; Vamoose.
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the ASC and Batman registers (A1 = return address)
;
; These registers must be restored in the given order. If the CDXA registers
; are restored in the incorrect order Batman will be confused and not function
; appropriately. Also if the FIFO control register is set prior to the SRC
; Time Increment it will not function properly.
;————————————————————————————————————————————————————————————————————————————————————————
RestoreASCBatman
MOVE.L ASCBase,A2
CMPI.B #batmanSnd,ascVersion(A2) ; is this a Batman?
BNE.S @NotBatman ; -> nope, that's all we save
MOVE.L A1,D2 ; save the return address
MOVEQ #$20,D1 ; reg D1 = channel offset (0=A,$20=B) <H24>
@restBatReg LEA $F10(a2),a1 ; restore CDXA coefficient regs ($F10-$F17) <H24>
ADDA.L D1,a1 ; add channel offset for A or B <H24>
MOVEQ #8-1,D0 ; <H24>
@restCDXA MOVE.B (SP)+,(a1)+ ; <H24>
DBRA D0,@restCDXA ; <H24>
LEA $F00(a2),a1 ; restore Batman channel control regs ($F00-$F09) <H24>
ADDA.L D1,a1 ; add channel offset for A or B <H24>
MOVEQ #10-1,D0 ; <H24>
@restBatC MOVE.B (SP)+,(a1)+ ; <H24>
DBRA D0,@restBatC ; <H24>
TST.L D1 ; Are we done with both channels <H24>
BEQ.S @restCont ; Yes??? Go on... <H24>
MOVEQ #0,D1 ; Set Channel A Offset <H24>
BRA.S @restBatReg ; restore channel B registers <H24>
@restCont
MOVE.B (SP)+,ascTestReg(a2) ; restore test control register <H24>
MOVEA.L D2,A1 ; restore return address <H24>
@NotBatman MOVE.B (SP)+,$80A(A2) ; restore Channel A play/record register
MOVE.B (SP)+,ascVolControl(A2) ; restore external sound volume control
MOVE.B (SP)+,ascMode(A2) ; restore chip mode
JMP (A1)
;————————————————————————————————————————————————————————————————————————————————————————
; Reenable Sound amps (A1 = return address) <H29>
;———————————————————————————————————————————————————————————————————————————————————————— |
RestoreDartAmp ; V
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 ; and finally to the sound register
; |
BSET #PontiSndLatchClr,(A0) ; pulse (positive) latch clear bit <H30>
BCLR #PontiSndLatchClr,(A0) ; <H30>
; <H30>
BCLR #PontiSndPwrOn,(A0) ; turn off sound power <H30>
; |
BCLR #PontiSndPWMOff,(A0) ; turn on power amps V
JMP (A1) ; done <H29>
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore misc PmgrVars (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestorePmgrMisc
MOVE.L A1,-(SP) ; push return address on stack
CLR.L -(SP) ; zero the buffer <H18>
MOVE.L SP,-(SP) ; pmRBuffer <H18>
MOVE.L (SP),-(SP) ; pmSBuffer <H18>
CLR.W -(SP) ; pmLength = 0 <H18>
MOVE.W #batteryRead,-(SP) ; pmCommand = batteryRead <H18>
MOVEA.L SP,A0 ; point to the parameter block <H18>
_PMgrOp ; send the command <H18>
MOVEA.L pmRBuffer(A0),A2 ; get pointer to receive buffer
MOVEA.L PmgrBase,a0 ; get pointer to globals
MOVE.B (A2),Charger(A0) ; Initialize charger state
LEA pmBlkSize(SP),SP ; Remove stack frame
RTS ; that's all folks
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the VIA1 registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreVIA1
MOVEA.L VIA,A2
MOVEM.W (SP)+,D0-D6 ; get the saved registers off the stack
MOVE.B D0,vBufB(A2) ; and stuff them back into the VIA
MOVE.B D1,vDIRB(A2)
MOVE.B D2,vBufA(A2)
MOVE.B D3,vDIRA(A2)
MOVE.B D4,vIER(A2)
MOVE.B D5,vACR(A2)
MOVE.B D6,vPCR(A2)
MOVE.B vT2CH(A2),vT2CH(A2) ; restart the timer
MOVE.B vT1CH(A2),vT1CH(A2)
JMP (A1)
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine to restore the VIA2 registers (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreVIA2
MOVEA.L VIA2,A2
MOVEM.W (SP)+,D0-D6 ; get the saved registers off the stack
MOVE.B D0,vBufB(A2) ; and stuff them back into the VIA
MOVE.B D1,vDIRB(A2)
MOVE.B D2,vBufA(A2)
MOVE.B D3,vDIRA(A2)
MOVE.B D4,vIER(A2)
MOVE.B D5,vACR(A2)
MOVE.B D6,vPCR(A2)
JMP (A1)
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine for clearing interrupts (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
WakeClrInts
MOVEM.L A0-A1,-(SP) ; save very important registers
MOVEA.L VIA,A0 ; get VIA base address
MOVE.B #(1<<ifIRQ)+(1<<ifCB1),vIFR(A0) ; clear PMGR interrupts
LEA -12(SP),SP ; read any pending interrupt data from the PMGR so we
MOVE.L SP,A0 ; don't hang in ADBReInit
ADDQ.L #2,A0 ;
MOVEQ #ReadINT,D0 ; PMGR command, get interrupt flags
MOVE.L A2,-(SP)
BigJSR PMGRrecv,A2 ;
MOVE.L (SP)+,A2
LEA 12(SP),SP ;
MOVEM.L (SP)+,A0-A1 ; restore very important registers
JMP (A1) ; go home
;————————————————————————————————————————————————————————————————————————————————————————
; Wakeup routine for setting sound (A1 = return address)
;————————————————————————————————————————————————————————————————————————————————————————
WakeSoundSet
MOVEM.L A0-A1,-(SP) ; save special registers
SUBQ.W #4,SP ; Create stack frame
MOVE.L SP,A0
MOVE.B #sndClrLtch,(A0) ; Clear the Sound latch
MOVEQ #1,D1 ; One long to send
MOVE.W #SoundSet,D0 ; PMGR command, Set Sound Control
MOVE.L A2,-(SP)
BigJSR PMGRsend,A2 ; have the PMGR clear the sound latch
MOVE.L (SP)+,A2
ADDQ.W #4,SP ; Remove stack frame
MOVEM.L (SP)+,A0-A1 ; restore special registers
JMP (A1) ; go home
;•••••••••••••••••••••••••••••••••• Screen Misc ••••••••••••••••••••••••••••••••••••••
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: RedrawScrn
;
; Inputs: A5 - Quickdraw globals
;
; Outputs: none
;
; Trashes: A0
;
; Function: updates the screen
;————————————————————————————————————————————————————————————————————————————————————————
RedrawScrn
BSR ScreenWakeInit ; update all slept devices <K14>
TST.B WWExist ; is the Window Manager initialized?
BNE.S @NoWW ; -> no, just leave the screen alone
SUBQ.W #4,SP ; Get some space on the stack <13>
MOVE.L SP,-(SP) ; Push pointer for GrafPort <13>
_GetPort ; Get our current port <13>
_RedrawAll ; CheckUpdate on all layers
_SetPort ; Restore port to original <13>
@NoWW
RTS ; That's all folks
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SaveRestoreLCD (SleepLCD/RestoreLCD)
;
; Inputs: D1 - 0 -> SaveLCD, non-zero -> RestoreLCD.
;
; Outputs: None
;
; Trashes: D0
;
; Function: This routine uses the VideoInfo record to tell it the DrHwID of the driver
; it is supposed to use in order to save the state of the LCD controller/panel.
;
; Notes: The SleepWake call in the video driver is required to do all that is necessary
; to save the state of LCD video controller so that it may be restored correctly
; upon wake. Also, the SleepWake call should paint the screen gray itself (because
; VRAM will have been non-refreshed during sleep) due to the fact that our having
; to make an addition control call from here could potentially be quite
; aesthetically unpleasing.
;————————————————————————————————————————————————————————————————————————————————————————
With SpBlock
SaveRestoreLCD
Move.l A0,-(SP) ; Save that register
Movea.l UnivInfoPtr,A0 ; Point to the ProductInfo record.
Adda.l VideoInfoPtr(A0),A0 ; Point to the VideoInfo record.
Move.w DrvrHwID(A0),D0 ; If the DrvrHwID is zero,
Beq.s @Done ; then just leave.
Suba.w #SpBlockSize,Sp ; Allocate an SpBlock on the stack.
Movea.l Sp,A0 ; Point to it with A0.
Clr.b spSlot(A0) ; Were only looking in Slot $0 here.
Clr.b spID(A0) ; Begin at sRsrcID 0.
Clr.b spExtDev(A0) ; No external device.
Clr.b spTBMask(A0) ; No mask in search.
Move.w #catDisplay,spCategory(A0) ; Look for: Display,
Move.w #typVideo,spCType(A0) ; Video,
Move.w #drSwApple,spDrvrSW(A0) ; Apple,
Move.w D0,spDrvrHw(A0) ; <DrHwID>.
Clr.l spParamData(A0) ; Look only for enabled sRsrcs.
Bset #foneslot,spParamData+3(A0) ; Limit search to this slot only.
_GetTypeSRsrc ; If we didnt find the target,
Bne.s @Cleanup ; then just leave.
Move.w spRefNum(A0),D0 ; If theres no driver, then
Beq.s @Cleanup ; just go on.
Suba.w #ioQElSize,Sp ; Allocate ioCore pBlock.
Movea.l Sp,A0 ; Set up for the control call:
Move.w D0,ioRefNum(A0) ; ioRefNum,
Move.w #cscSleepWake,csCode(A0) ; csCode,
Move.b D1,-(Sp) ; csParam,
Move.l Sp,csParam(A0) ; csParamPtr,
_Control ,Immed ; SleepWake.
Tst.b (Sp)+ ; Remove param from stack.
Adda.w #ioQElSize,Sp ; Deallocate ioCore pBlock.
@Cleanup Adda.w #SpBlockSize,Sp ; Deallocate SpBlock.
@Done Movea.l (SP)+,A0 ; restore that register
Rts
Endwith
;_PaletteDispatch OPWORD $AAA2 ; PaletteDispatch is NOT defined in this ROM.
;selectSetDepth EQU $0A13 ; SetDepth -> $0A is paramsize, $13 is the selector.
SetScreenBrightness EQU $4301
GetScreenBrightness EQU $5301 ;
DimLevel EQU 1 ;
VidStkFrame RECORD 0, DECR
VidStkCntBlk DS.B IOVQElSize ; control call parm block
VidStkVDPageInfo DS.B VDPageInfo ; params
VidStkFrameSize EQU * ; size of frame
ENDR
;———————————————————————————————————————————————————————————————————————————————————————— <Kxx>
; Routine: ScreenWakeInit |
; v
; Inputs: none
;
; Outputs: none
;
; Trashes: D0
;
; Function: SetDepth in order to set the driver in appropriate state and to tell Quickdraw
; to rebuild the world.
;————————————————————————————————————————————————————————————————————————————————————————
ScreenWakeInit
ScreenWakeInitRegs REG D1-D2/A0-A4
WITH VidStkFrame,VDPageInfo
LINK A6,#VidStkFrameSize ; allocate variable space
MOVEM.L ScreenWakeInitRegs,-(SP) ; save them regs
LEA VidStkCntBlk(A6),A3 ; get pointer to IOPB
LEA VidStkVDPageInfo(A6),A4 ; get pointer to csParams
MOVE.L A4,csParam(A3) ; set csParams
MOVE.W #cscPowerSelect,csCode(A3) ; cscPowerSelect
MOVE.L DeviceList,D1 ; If the DeviceList is empty,
BEQ.S @ScreenWakeInitDone ; then we cant do anything!
MOVEQ #0,D2 ; Initialize PowerSelect supported flag
@ScreenWakeInitLp ; DO {
MOVEA.L D1,A2 ; Get gDevice Handle
MOVEA.L (A2),A2 ; Dereference the handle
MOVEQ #0,D0 ; Clear both halves of D0.l.
MOVE.W gdRefNum(A2),D0 ; Get driver refnum.
BEQ.S @NoSetDepth ; If not non-zero, skip.
MOVEA.L A3,A0 ; A0 := IOPB
ORI.W #-1,D2 ; Set Flag
MOVE.L D1,-(SP) ; Push gdHandle
MOVE.W gdMode+2(A2),-(SP) ; Push the depth
CLR.L gdMode(A2) ; Clear it so stupid trap doesn't freak out
CLR.L -(SP) ; Clear all flags
MOVE.W #selectSetDepth,D0 ; Set selector to set depth
_PaletteDispatch ; Call it
@NoSetDepth
MOVE.L gdNextGD(A2),D1 ; Device := NextDevice
BNE.S @ScreenWakeInitLp ; } While !EndOfDeviceLoop
@ScreenWakeInitDone
MOVEM.L (SP)+,ScreenWakeInitRegs ; restore reg
UNLK A6 ; release stack frame
RTS ; that's all folks
;———————————————————————————————————————————————————————————————————————————————————————— <H32>
; Routine: VidLowPwrSelect |
; v
; Inputs: D0 0 = PowerOn , nonzero = PowerDown
;
; Outputs: none
;
; Trashes: D0
;
; Function: Call the video driver to set the power state to the appropriate position.
; In the case of power up, power up the hardware and call SetDepth in order to
; set the driver in appropriate state and to tell Quickdraw to rebuild the
; world.
;————————————————————————————————————————————————————————————————————————————————————————
VidLowPwrSelect
VidLowPwrSelectRegs REG D1-D2/A0-A4
WITH VidStkFrame,VDPageInfo
LINK A6,#VidStkFrameSize ; allocate variable space
MOVEM.L VidLowPwrSelectRegs,-(SP) ; save them regs
LEA VidStkCntBlk(A6),A3 ; get pointer to IOPB
LEA VidStkVDPageInfo(A6),A4 ; get pointer to csParams
MOVE.L A4,csParam(A3) ; set csParams
Move.l #powerSelSig,csParam+4(A3) ; (For Radius, csParams is not a pointer in some cases.)
MOVE.W #cscPowerSelect,csCode(A3) ; cscPowerSelect
MOVE.L DeviceList,D1 ; If the DeviceList is empty,
Beq.s @VidLowPwrSelectDone ; then we cant do anything!
MOVEQ #0,D2 ; Initialize PowerSelect supported flag
TST.L D0 ; IF PowerDown THEN
BNE @VidPowerDown ; branch…
@PwrUpgDevLoop ; DO {
MOVEA.L D1,A2 ; Get gDevice Handle
MOVEA.L (A2),A2 ; Dereference the handle
Moveq #0,D0 ; Clear both halves of D0.l.
MOVE.W gdRefNum(A2),D0 ; Get driver refnum.
Beq.s @NoSetDepth ; If not non-zero, skip.
MOVEA.L A3,A0 ; A0 := IOPB
Bsr PowerSelectSupported ; IF cscPowerSelect NOT supported THEN
Beq.s @NoSetDepth ; just go on.
Move.w D0,ioRefNum(A0) ; Set driver refnum
CLR.W csMODE(A4) ; Set PowerUpMode in csMode
_Control ,IMMED ; Power Up Device
BNE.S @NoSetDepth ; IF cscPowerSelect supported THEN
ORI.W #-1,D2 ; Set Flag
MOVE.L D1,-(SP) ; Push gdHandle
MOVE.W gdMode+2(A2),-(SP) ; Push the depth
CLR.L gdMode(A2) ; Clear it so stupid trap doesn't freak out
CLR.L -(SP) ; Clear all flags
MOVE.W #selectSetDepth,D0 ; Set selector to set depth
_PaletteDispatch ; Call it
@NoSetDepth
MOVE.L gdNextGD(A2),D1 ; Device := NextDevice
BNE.S @PwrUpgDevLoop ; } While !EndOfDeviceLoop
TST.W D2 ; IF SetDepthCalled THEN
BEQ.S @NoRestore ;
TST.B WWExist ; is the Window Manager initialized?
BNE.S @NoRestore ; -> no, just leave the screen alone
SUBQ.W #4,SP ; Get some space on the stack
MOVE.L SP,-(SP) ; Push pointer for GrafPort
_GetPort ; Get our current port
_RedrawAll ; CheckUpdate on all layers
_SetPort ; Restore port to original
@NoRestore
_ShowCursor ; Show Cursor
@VidLowPwrSelectDone
MOVEM.L (SP)+,VidLowPwrSelectRegs ; restore reg
UNLK A6 ; release stack frame
RTS ; that's all folks
; Power-Down Video Devices
; Set up IOPB for control call
@VidPowerDown
Moveq #0,D2 ; Assume that were not hiding the cursor.
MOVEA.L A3,A0 ; A0 := IOPB
@PwrDowngDevLoop ; DO {
MOVEA.L D1,A2 ; Get gDevice Handle
MOVEA.L (A2),A2 ; Dereference the handle
Moveq #0,D0 ; Clear both halve of D0.l.
Move.w gdRefNum(A2),D0 ; Get driver refNum
Beq.s @NextGD ; If not non-zero, skip.
Bsr PowerSelectSupported ; If cscPowerSelect NOT supported THEN
Beq.s @NextGD ; just go on
Move.w D0,ioRefNum(A0) ; Set driver refnum
MOVE.W #-1,csMODE(A4) ; Set PowerDown in csMode
_Control ,IMMED ; Power Down Device
Bne.s @NextGD ; If failed, keep going.
Moveq #-1,D2 ; Otherwise, hiding the cursor is okay.
@NextGD MOVE.L gdNextGD(A2),D1 ; Device := NextDevice
BNE.S @PwrDowngDevLoop ; } While !EndOfDeviceLoop
; Kill the BackLight. <H33>
LEA DBLiteBackLite,A2 ; Get pointer to Backlight driver name. |
MOVE.L A2,ioFileName(A0) ; Load it. v
_Open ; Open driver to get the refNum.
BNE.S @NoDriver ; IF Open==Successful THEN
MOVE.W #GetScreenBrightness,csCode(A0) ; get current brightness level <H49>
_Status ,IMMED ; <H49>
CMP.W #DimLevel,csParam(a0) ; only dim if level is greater than dim value <H49>
BLE.S @NoDriver ; level is already lower than dimming value <H49>
MOVE.W #SetScreenBrightness,csCode(A0) ; turn off screen brightness
MOVE.W #DimLevel,csParam(A0) ; set brightness level <H49>
_Control ,IMMED ; do it
Bne.s @NoDriver ; don't hide cursor if failed
Ori.w #-1,D2 ; otherwise, flag that we can hide the cursor
@NoDriver Tst.l D2 ; If we shouldnt hide the cursor,
Beq.s @VidLowPwrSelectDone ; then just go on.
_HideCursor ; Otherwise, hide it.
BRA.S @VidLowPwrSelectDone ; And go on.
ENDWITH
STRING Pascal
DBLiteBackLite DC.B '.Backlight' ; Name of Backlight Driver for DBLite.
ALIGN 2
VSCDrvrName Dc.b '.VSC_Video' ; Name of Mini/Duo Dock Video Driver.
Align 2
KeyStoneDrvrName Dc.b '.Display_Video_Apple_ViSC' ; Name of Dart-class version of the VSC Video Driver.
Align 2
STRING Asis
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: PowerSelectSupported
;
; Inputs: D0.l - refNum of a video driver
; A0.l - pointer to video driver control/status IOPB for cscPowerSelect
;
; Outputs: D0.w - if non-zero, is video drivers refNum and PowerSelect is
; supported by the video driver.
;
; Trashes: D0
;
; Function: Returns whether or not a particular video driver supports the cscPowerSelect
; call. Note that for the original two Apple video drivers that supported
; this call, we just do a name check. From now on, though, we call the
; corresponding status call. If we get back an error, we assume that the
; call is not supported. Otherwise, we check the csData field for the
; appropriate signature to be sure that cscPowerSelect is really supported.
;————————————————————————————————————————————————————————————————————————————————————————
PowerSelectSupported
Move.w D0,-(Sp) ; Save the refNum for later.
Beq @ExitNow ; If nil, then just leave.
; Get the video drivers name…
;
Movem.l A0-A1/D7,-(Sp) ; Save some work registers.
Not.w D0 ; Convert the refNum into…
Lsl.w #2,D0 ; …a UTable index.
Add.l UTableBase,D0 ; Get a pointer to the AuxDCEHandle.
Movea.l D0,A0 ; Get it into A0.
Movea.l (A0),A0 ; Get the AuxDCEHandle.
Movea.l (A0),A0 ; Get the AuxDCEPtr.
Move.w dCtlFlags(A0),D0 ; Get the device flags.
Movea.l dCtlDriver(A0),A0 ; Get the driver.
Btst #dRAMBased,D0 ; If its not in RAM, then
Beq.s @GetName ; its already a pointer.
Movea.l (A0),A0 ; Otherwise, get pointer to driver.
@GetName Lea drvrName(A0),A0 ; Point to the driver name.
Move.l A0,D7 ; Save it for later.
; Check for the Mini/Duo Dock Video Driver…
;
Moveq #0,D0 ; Clear both halves of D0.l.
Move.b (A0)+,D0 ; Get the length of the driver name.
Swap D0 ; Save it.
Lea VSCDrvrName,A1 ; Point to the Mini/Duo Dock Video Drivers name.
Move.b (A1)+,D0 ; Get the length of the driver name.
_CmpString ; Compare the two names.
Tst.w D0 ; If they match,
Beq.s @Supported ; then just go on.
; Check for the Dart-class version of the VSC Video Driver.
;
Movea.l D7,A0 ; Re-point to the driver were checking.
Moveq #0,D0 ; Clear both halves of D0.
Move.b (A0)+,D0 ; Get the length of the driver name.
Swap D0 ; Save it.
Lea KeyStoneDrvrName,A1 ; Point to the Dart-class version of the VSC Video Driver.
Move.b (A1)+,D0 ; Get the length of the driver name.
_CmpString ; Compare the two names.
Tst.w D0 ; If they match,
Beq.s @Supported ; then just go on.
; Now, generically check the driver by making the cscPowerSelect status call…
;
With VDPageInfo
Movem.l (Sp)+,A0-A1/D7 ; Restore work registers.
Move.l A0,D0 ; Save A0 (IOPB ptr) for now.
Movea.l csParam(A0),A0 ; Point to csParams data.
Clr.l csData(A0) ; Clear the verification field.
Movea.l D0,A0 ; Restore A0.
Move.w (Sp),ioRefNum(A0) ; Get the driver refNum.
_Status ,Immed ; If cscPowerSelect is not supported,
Bne.s @NotThere ; then just say so.
Move.l A0,-(Sp) ; Save A0.
Movea.l csParam(A0),A0 ; Point to the csParams data.
Cmpi.l #powerSelSig,csData(A0) ; Check for cscPowerSelect.
Movea.l (Sp)+,A0 ; Restore A0.
Beq.s @Supported1 ; If cscPowerSelect is supported, then just go on.
@NotThere Addq #2,Sp ; Strip refNum off the stack.
Moveq #0,D0 ; Say that cscPowerSelect is not supported.
Rts ; And leave.
Endwith
; Clean up and go home…
;
@Supported Movem.l (Sp)+,A0-A1/D7 ; Restore the work registers.
@Supported1 Move.w (Sp)+,D0 ; Get the refNum back into D0.
@ExitNow Rts ; Return to caller.
;•••••••••••••••••••••••••••••••••••• Battery Stuff •••••••••••••••••••••••••••••••••••••
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: GetLevel
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - normalized battery level (-1 to 4)
; CCR - BNE if a valid battery level is being returned
;
; Trashes: D0-D3, A0
;
; Function: Reads the battery power level from the Power Manager and adds this value into
; an eight value circular queue. If the queue is full then an average of these
; values is calculated. Next, the averaged value is compared with the warning
; and cutoff values in PRAM to determine if the average is greater then reserve
; or what fractional part of reserve (1, 3/4, 1/2, or 1/4).
;————————————————————————————————————————————————————————————————————————————————————————
GetLevel CLR.L -(SP) ; make space for a buffer
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #batteryNow,-(SP) ; pmCommand = get battery data
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVEA.L SP,A0 ; point to the buffer
MOVEQ #0,D3
MOVE.B (A0)+,Charger(A2) ; get the charger state
MOVE.B (A0),D3 ; and the battery level
ADDQ.W #4,SP ; toss the stack frame
BTST #ChrgState,Charger(A2) ; get the charger state (connected/disconnected)
BEQ.S @ChargeSame ; -> no change in charger state
ST TOdirtyFlag(A2) ; Flag TOs need updating
@ChargeSame MOVEQ #0,D0
MOVE.B BatQIndex(A2),D0 ; get the next index into the circular queue
SUBQ.B #1,D0
BPL.S @IndexOK ; -> index is still valid
MOVEQ #7,D0 ; it wrapped, so reset it
@IndexOK MOVE.B D0,BatQIndex(A2) ; save the new index
MOVE.B D3,BatQ(A2,D0.W) ; put the latest battery level into queue
TST.B BatQ(A2) ; wait for full queue before averaging
BEQ.S GetLevel
MOVEQ #0,D3
MOVE.B BatQ(A2),D0 ; calculate the average of the last 8 samples
ADD.W D0,D3
MOVE.B BatQ+1(A2),D0
ADD.W D0,D3
MOVE.B BatQ+2(A2),D0
ADD.W D0,D3
MOVE.B BatQ+3(A2),D0
ADD.W D0,D3
MOVE.B BatQ+4(A2),D0
ADD.W D0,D3
MOVE.B BatQ+5(A2),D0
ADD.W D0,D3
MOVE.B BatQ+6(A2),D0
ADD.W D0,D3
MOVE.B BatQ+7(A2),D0
ADD.W D0,D3
LSR.W #1,D3 ; D3 = 4*avg
MOVEQ #0,D2
MOVE.B LowWarn(A2),D2 ; D2 = low warning level
MOVEQ #0,D1
MOVE.B CutOff(A2),D1 ; D1 = cutoff level
SUB.W D1,D2 ; D2 = warning - cutoff
ASL.W #2,D1 ; D1 = 4*cutoff
MOVEQ #4,D0 ; level 4
ADD.W D2,D1 ; D1 = 4*cutoff + 1(warning - cutoff)
CMP.W D1,D3 ; power ≤ 1/4 reserve
BLS.S @foundlevel
MOVEQ #3,D0 ; level 3
ADD.W D2,D1 ; D1 = 4*cutoff + 2(warning - cutoff)
CMP.W D1,D3 ; power ≤ 1/2 reserve
BLS.S @foundlevel
MOVEQ #2,D0 ; level 2
ADD.W D2,D1 ; D1 = 4*cutoff + 3(warning - cutoff)
CMP.W D1,D3 ; power ≤ 3/4 reserve
BLS.S @foundlevel
MOVEQ #1,D0 ; level 1
ADD.W D2,D1 ; D1 = 4*cutoff + 4(warning - cutoff)
CMP.W D1,D3 ; power ≤ reserve
BLS.S @foundlevel
MOVEQ #0,D0 ; level 0
MOVE.W Hysteresis(A2),D2 ; D2 = hysteresis
ASL.W #2,D2 ; D2 = 4 * hysteresis
ADD.W D2,D1 ; D1 = 4*cutoff + 4(warning - cutoff) + 4*hysteresis
CMP.W D1,D3 ; power ≤ reserve + hysteresis
BLS.S @foundlevel
MOVEQ #-1,D0 ; power > reserve + hysteresis
@foundlevel LSR.W #2,D3 ; D3 = average
MOVE.B D3,BatAvg(A2) ; save it
TST.B BatQ(A2) ; set data valid condition
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: GetExtLevel
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - normalized battery level (-1 to 4)
; CCR - BNE if a valid battery level is being returned
;
; Trashes: D0-D3, A0
;
; Function: Reads the extended battery power level from the Power Manager (which is
; pre-averaged by the PMGR). Next, the value is compared with the warning
; and cutoff values in PRAM to determine if the average is greater then
; reserve or what fractional part of reserve (1, 2/3, or 1/3).
;
; Note: The extended battery status command supports a word-sized battery
; level. Currently the PMGR on DBLite uses a 9-bit A/D to sample
; the battery voltage.
;
; The battery warning levels returned will be zero if no battery is
; currently connected.
;————————————————————————————————————————————————————————————————————————————————————————
GetExtLevel CLR.W -(SP) ; setup a buffer for the result
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readBattWarning,-(SP) ; pmCommand = get warning/cutoff levels
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; go get them
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVE.W (SP)+,LowWarn(A2) ; save the new warning/cutoff levels
CLR.L -(SP)
CLR.L -(SP)
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readExtBatt,-(SP) ; pmCommand = get extended battery data
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVEA.L SP,A0 ; point to the buffer
MOVEQ #%00001011,D0 ; mask off the bits we want in the flags byte,
AND.B (A0),D0
MOVE.B Charger(A2),D1 ; get the old charger state, <H13>
MOVE.B D0,Charger(A2) ; and save the new charger state
MOVE.B (A0)+,D0 ; get the unmodified flags <H41>
EOR.B D0,D1 ; has the charger state changed since last time? <H13>
BTST #HasCharger,D1 ; <H13>
BEQ.S @ChargeSame ; -> no <H13>
ST TOdirtyFlag(A2) ; yes, flag that timeouts need updating <H13>
@ChargeSame MOVE.W (A0),D3
LSR.W #1,D3
MOVE.B D3,BatAvg(A2) ; save the 8-bit battery voltage
ADD.W (A0)+,D3 ; D3 = 3*(8 bit battery voltage)
ADDQ.W #8,SP ; toss the buffer
BTST #HasCharger,D0 ; is a charger connected? <H13>
BNE.S @HaveCharger ; -> yes, we don't care about the battery level <H13>
BTST #2,D0 ; is a battery connected? <H41>
BEQ.S @HaveCharger ; -> no, don't bother with battery level
MOVEQ #0,D2 ; <H44>
MOVE.B LowWarn(A2),D2 ; D2 = low warning level |
MOVEQ #0,D1 ; V
MOVE.B CutOff(A2),D1 ; D1 = cutoff level
SUB.W D1,D2 ; D2 = warning - cutoff
MOVE.W D1,D0
ADD.W D0,D1
ADD.W D0,D1 ; D1 = 3*cutoff
MOVEQ #4,D0 ; level 4
ADD.W D2,D1 ; D1 = 3*cutoff + 1(warning - cutoff)
CMP.W D1,D3 ; power ≤ 1/3 reserve
BLS.S @foundlevel
MOVEQ #3,D0 ; level 3
ADD.W D2,D1 ; D1 = 3*cutoff + 2(warning - cutoff)
CMP.W D1,D3 ; power ≤ 2/3 reserve
BLS.S @foundlevel
; (level 2 is not used, so we don't return it)
MOVEQ #1,D0 ; level 1
ADD.W D2,D1 ; D1 = 3*cutoff + 3(warning - cutoff)
CMP.W D1,D3 ; power ≤ reserve
BLS.S @foundlevel
MOVEQ #0,D0 ; level 0
MOVE.W Hysteresis(A2),D2 ; D2 = hysteresis
ADD.W D2,D1
ADD.W D2,D1
ADD.W D2,D1 ; D1 = 3*cutoff + 3(warning - cutoff) + 3*hysteresis
CMP.W D1,D3 ; power ≤ 1.0 reserve + hysteresis
BLS.S @foundlevel
@HaveCharger
MOVEQ #-1,D0 ; return a "charged" battery level in case someone cares
@foundlevel MOVEQ #1,D1 ; always return BNE for data valid
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: LeadScaledBatteryInfo (PowerDispatch selector #9)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - bits 31: 1=battery installed
; 30: 1=battery is charging
; 29: 1=charger connected
; 23-16: warning level (0-255)
; 15: don't use this one (needs to be set if the selector isn't implemented)
; 7- 0: battery level (0-255)
;
; Trashes: D1, D2, A0
;
; Function: Returns scaled warning and battery levels, plus a couple of flags for
; portables that support sealed lead acid batteries.
;————————————————————————————————————————————————————————————————————————————————————————
LeadScaledBatteryInfo
MOVEQ #3,D0 ; mask off the battery charging and charger installed bits
AND.B charger(a2),D0 ; <H39>
MOVEQ #0,D2 ; get the maximum battery voltage
MOVE.B @MaxVolts(D0),D2
SUB.B CutOff(A2),D2 ; <H37>
ADDQ.B #1<<2,D0 ; set the battery installed bit
ROR.W #3,D0 ; put the battery flags into bits 15-13 (temporarily)
MOVEQ #0,D1 ; scale the warning level (256*warning/max)
MOVE.B LowWarn(A2),D1
SUB.B CutOff(A2),D1 ; <H37>
BSR.S ScaleLevel ; pin the level and save it
SWAP D0 ; put it all in the upper word
MOVEQ #0,D1 ; scale the battery level (256*batt/max)
move.b BatAvg(A2),d1 ; get the current averaged battery <H39>
SUB.B CutOff(A2),D1 ; <H37>
BSR.S ScaleLevel ; pin the level and save it
RTS
@MaxVolts DC.B 123 ; [6.35v] not charging, no charger
DC.B 188 ; [7.00v] not charging, has charger
DC.B 123 ; [6.35v] is charging, no charger (can't get here)
DC.B 208 ; [7.20v] is charging, has charger
ScaleLevel ASL.L #8,D1 ; multiply by 256
DIVU D2,D1 ; divide a level by the maximum
CMPI.W #255,D1 ; higher than max (well, it _might_ happen)?
BLS.S @SaveLevel ; -> no, use it as is
MOVE.B #255,D1 ; yes, pin it at maximum
@SaveLevel MOVE.B D1,D0 ; save the scaled level
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: MultiScaledBatteryInfo (PowerDispatch selector #9)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - bits 31: 1=battery installed
; 30: 1=battery is charging
; 29: 1=charger connected
; 23-16: warning level (0-255)
; 15: don't use this one (needs to be set if the selector isn't implemented)
; 7- 0: battery level (0-255)
;
; Trashes: D1, D2, A0
;
; Function: Returns scaled warning and battery levels, plus a couple of flags for
; portables that support multiple battery types. If no battery is currently
; connected, it will return zero for both the warning and battery levels.
; It uses the extended battery status command which returns the following info:
;
; +0 flags (bits)
; 7: chargeable battery
; 6: "energy used" count valid
; 5: 0
; 4: battery termperature valid
; 3: dead battery
; 2: battery connected
; 1: hi-charge enabled
; 0: charger installed
; +1 voltage (H)
; +2 voltage (L)
; +3 ambient temperature (°C)
; +4 battery temperature (°C)
; +5 power usage rate
; +6 energy used (H)
; +7 energy used (L)
;
; and the battery info command, which returns the following info:
;
; +0 max energy used count (H)
; +1 max energy used count (L)
; +2 min voltage--charging (H)
; +3 min voltage--charging (L)
; +4 max voltage--charging (H)
; +5 max voltage--charging (L)
; +6 min voltage--discharging (H)
; +7 min voltage--discharging (L)
; +8 max voltage--discharging (H)
; +9 max voltage--discharging (L)
;————————————————————————————————————————————————————————————————————————————————————————
MultiScaledBatteryInfo
LINK A6,#0
; get parameters associated with the current type of battery...
CLR.W -(SP) ; put a buffer on the stack
CLR.L -(SP)
CLR.L -(SP)
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readBatteryInfo,-(SP) ; pmCommand = return battery info
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
; get the current battery state and battery level...
CLR.L -(SP)
CLR.L -(SP)
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readExtBatt,-(SP) ; pmCommand = get extended battery data
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVEA.L SP,A0 ; point to the buffer
MOVEQ #%01000111,D0 ; mask off the "energy used" count valid,
AND.B (A0)+,D0 ; battery installed, charging, and charger connected bits
ROR.W #3,D0 ; shift them into bits 15-13 and 3 (temporarily)
MOVE.L (A0)+,D2 ; get the battery voltage into the upper word (NOTE: unaligned read)
ADDQ.W #1,A0 ; skip over the power usage rate
MOVE.W (A0)+,D2 ; get the "energy used" count into the lower word
MOVE.L A0,SP ; toss the buffer
TST.W D0 ; is a battery installed?
BPL.S @NoBattery ; -> no, just swap the flags and exit
BCLR #6-3,D0 ; is the "energy used" count valid?
BEQ.S @UseVolts ; -> no, use the voltages
; calculate the current level based on the "energy used" count...
@UseCount SWAP D0 ; put the flags into the upper word, set warning level=0
MOVEQ #0,D1 ; get the maximum energy count (zero-extended)
MOVE.W (SP),D1
SUB.W D2,D1 ; calculate how much energy is left (max-used)
BLE.S @Done ; -> max≤used, so pin at zero
MOVE.W (SP),D2 ; get the maximum
BSR.S ScaleLevel ; scale the level and save it
BRA.S @Done
; calculate the current level based on voltages...
@UseVolts LEA 4(SP),A0 ; point to the charge parameters
BTST #14,D0 ; are we charging?
BNE.S @Charging ; -> yes, we're pointing to the right place
ADDQ.W #4,A0 ; no, point to the discharge parameters
@Charging MOVE.W (A0),D2 ; calculate max-min
SUB.W -(A0),D2
BLE.S @NoBattery ; -> max≤min (strange…), so bail
BTST #14,D0 ; are we charging? <H37>
BNE.S @NoWarning ; -> yes, there's no warning level <H37>
MOVEQ #0,D1
MOVE.B LowWarn(A2),D1 ; calculate warning-min
ADD.B D1,D1
SUB.W (A0),D1
BLE.S @NoWarning ; -> warning≤min, so pin at zero
BSR.S ScaleLevel ; scale the level and save it
@NoWarning SWAP D0 ; put it all in the upper word
MOVE.L D2,D1 ; get the battery voltage
CLR.W D1 ; and zero extend it
SWAP D1
SUB.W (A0),D1 ; calculate battery-min
BLE.S @Done ; -> battery≤min, so pin at zero
BSR.S ScaleLevel ; scale the level and save it
@Done UNLK A6 ; get rid of any lingering buffers
RTS
@NoBattery CLR.B D0 ; make sure the battery level is zero
SWAP D0 ; put the flags in the upper word
BRA.S @Done ; and exit
;———————————————————————————————————————————————————————————————————————————————————————— <H54>
; Routine: LeadAbsoluteBatteryVoltage
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - fixed-point representation of the absolute battery voltage
;
; Trashes: none
;
; Function: Calculates the absolute battery voltage for lead acid batteries. The result
; is returned as a fixed point number (16 bits integer + 16 bits fraction),
; giving a range from 0 to 32767.999984741 volts. This should be enough to
; handle the next few batteries we do.
;
; For lead acid batteries, the voltage is calculated as:
;
; voltage = ((power/100) + 5.12) volts
;
; For a power range of 0 to 255, we get a voltage range of 5.12 to 7.67 volts.
;————————————————————————————————————————————————————————————————————————————————————————
LeadAbsoluteBatteryVoltage
MOVEQ #0,D0 ; zero-extend the battery level
MOVE.B BatAvg(A2),D0
SWAP D0 ; convert it to fixed-point
DIVU #100,D0 ; divide by 100 to convert to relative volts
SWAP D0 ; get the result back in the right order
ADDI.L #(5<<16)+(65536*12/100),D0 ; add 5.12v to convert to absolute
RTS
;———————————————————————————————————————————————————————————————————————————————————————— <H54>
; Routine: PGEAbsoluteBatteryVoltage
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - fixed-point representation of the absolute battery voltage
;
; Trashes: A0, D1
;
; Function: Calculates the absolute battery voltage for PG&E-based machines. The result
; is returned as a fixed point number (16 bits integer + 16 bits fraction),
; giving a range from 0 to 32767.999984741 volts. This should be enough to
; handle the next few batteries we do.
;
; PG&E essentially uses a 9-bit A/D for a voltage range of 7 to 21 volts.
; So the voltage is calculated as:
;
; voltage = ((power*14/512) + 7) volts
;————————————————————————————————————————————————————————————————————————————————————————
PGEAbsoluteBatteryVoltage
CLR.L -(SP) ; allocate space for the extended battery info
CLR.L -(SP)
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength = 0
MOVE.W #readExtBatt,-(SP) ; pmCommand = get extended battery data
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVEQ #0,D0
MOVEA.L SP,A0 ; point to the buffer
BTST #2,(A0)+ ; is a battery connected?
BEQ.S @NoBattery ; -> no, we're done
MOVEQ #14,D0 ; battery level * 14
MULU (A0),D0 ; (NOTE: unaligned read)
SWAP D0 ; convert it to fixed point
MOVEQ #9,D1
LSR.L D1,D0 ; divide by 512 to convert to relative volts
ADDI.L #7<<16,D0 ; add 7v to convert to absolute
@NoBattery ADDQ.W #8,SP ; toss the buffer
RTS
;•••••••••••••••••••••••••••••••••••••• Utilities •••••••••••••••••••••••••••••••••••••••
;———————————————————————————————————————————————————————————————————————————————————————— <H22>
; PostUserNmMsg - post user warning notification msg
;
; General routine which will post a user warning notification mgr message using the
; "UNmQEntry" PmgrRec notification mgr record.
;
; Input: a0.l = ptr to notification string
; d0.w = indicates which completion routine
; 0 -> does nothing - leaves flashing icon (default)
; 1 -> removes message and icon
;
; Output: none
;
Export PostUserNmMsg
PostUserNmMsg
@regs reg d1/a0/a2
movem.l @regs,-(sp)
movea.l PmgrBase,a2 ; a2 = ptr to pmgr globals
bset.b #PmgrAvoidUsrMsg,PmgrFlags1(a2) ; are warning messages enabled?
bne.s @skip ; not enabled - skip it
move.l a0,d1 ; is there a string? <H26>
beq.s @skip ; no message to post
lea UNmQEntry(a2),a0 ; addr of notification record
move.l d1,nmStr(a0) ; set the string
move.w #8,qType(a0)
move.l #-1,nmSound(a0) ; use default sound
clr.w nmMark(a0) ; No mark
move.l lpSICNHndl(a2),nmIcon(a0) ; Use the icon
lea @nmproc,a2 ; no completion routine
subq.w #1,d0 ; the "other" completion routine? <H26>
bne.s @postmsg ; no - use default <H26>
lea @oneShot,a2 ; use routine which removes icon <H26>
@postMsg
move.l a2,nmResp(a0) ; set completion routine
_NMInstall ; post message
@skip
movem.l (sp)+,@regs
@nmproc rts ; empty completion routine <H26>
@oneShot ; <H26>
movea.l (sp)+,a1 ; save return addr <H26>
movea.l (sp)+,a0 ; get ptr to BNmQEntry <H26>
_NMRemove ; remove the bad battery notification <H26>
movea.l PmgrBase,a0 ; get ptr to pmgr globals <H26>
bclr.b #PmgrAvoidUsrMsg,PmgrFlags1(a0) ; allow user messages again <H26>
jmp (a1) ; return to caller <H26>
;••••••••••••••••••••••••••••••••••••••• ModemTables •••••••••••••••••••••••••••••••••••••••• <H31>
;————————————————————————————————————————————————————————————————————————————————————————
; Modem Table
;
; Tables of offsets to low level hardware dependent routines which are used for
; internal modem control
;————————————————————————————————————————————————————————————————————————————————————————
ALIGN 4
DC.L PrimsTypePtr ; flags
DC.L (ModemTableEnd-ModemTable) ; size of table
ModemTable DC.L StdModemOn-ModemTable ; standard routine to turn on modem
DC.L StdModemOff-ModemTable ; standard routine to turn off modem
DC.L StdModemType-ModemTable ; standard routine to get modem type
ModemTableEnd
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: TurnModemPowerOn/Off
;
; Input: a0.l = ptr to powermanager pb + 4 byte general data buffer(pmData)
; - pre-initialized so pmSend/pmReceive points to pmData
; d1.b = modem status bits from power manager
;
; Outputs: none
;
; Trashes: none
;
; Function: Power control for the internal modem
;
;————————————————————————————————————————————————————————————————————————————————————————
TurnModemPowerOff
bclr.l #ModemPwr,d1 ; clear bit in saved modem status bits
bra.s SetData
TurnModemPowerOn
and.b #7,d1 ; mask only <ring wakeup><port select><modem power>
bset.l #ModemPwr,d1 ; set bit in saved modem status bits
SetData move.b d1,pmData(a0) ; turn on +5V and -5V to modem bit
move.w #1,pmLength(a0) ; xmit one byte
move.w #modemSet,pmCommand(a0) ; modem set command
_PmgrOp ; turn on +5V and -5V to modem
rts
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: Enable/DisableModem
;
; Input: a0.l = ptr to powermanager pb + 4 byte general data buffer
;
; Outputs: none
;
; Trashes: none
;
; Function: Controls the modem enable line
;
;————————————————————————————————————————————————————————————————————————————————————————
DisableModem
move.b #ModemOff,pmData(a0) ; disable modem - sense of bit is reversed
bra.s SetCount
EnableModem
move.b #ModemOn,pmData(a0) ; enable modem - sense of bit is reversed
SetCount move.w #1,pmLength(a0) ; xmit one byte
move.w #powerCntl,pmCommand(a0) ; power control command
_PmgrOp ; call the power manager
rts
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: TurnOffModemSoundSelect
;
; Input: none
;
; Outputs: none
;
; Trashes: d0
;
; Function: turns off input source if modem selected
;
;————————————————————————————————————————————————————————————————————————————————————————
TurnOffModemSoundSelect
jsrTBL sndInputSource ; is a sound source selected?
cmp.B #2,D0 ; is the modem input selected ?
bne.s @exitSoundInput ; continue with code
move.b #0,d0 ; get current volume
jsrTBL sndPlayThruVol ; set volume for playthrough
moveq.l #sndInputOff,d0
jsrTbl sndInputSelect ; select aux source
@exitSoundInput
rts
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: DelayNMsec
;
; Input: d0.l = msec to delay
;
; Outputs: none
;
; Trashes: none
;
; Function: Spin wait for N milliseconds
;
;————————————————————————————————————————————————————————————————————————————————————————
EXPORT DelayNMsec
DelayNMsec
@savedregs reg d0-d1 ; working set of register
movem.l @savedregs,-(sp) ; save working set
move.w d0,d1 ; number of msec
subq #1,d1 ; subtract 1 for dbra loop
@msec move.w TimeDBRA,d0 ; load 1ms delay in d0
@Delay dbra d0,@Delay ; wait 1 ms
dbra d1,@msec ; repeat 1ms d1 times
movem.l (sp)+,@savedregs ; restore working set
rts
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: StdModemOn
;
; Input: a0.l = ptr to powermanager pb + 4 byte general data buffer
; d1.b = modem status bits from power manager
;
; Outputs: condition codes
;
; Trashes: d0
;
; Function: Power the internal dartanian modem
;
; The following is a summary of the devices and which power manager commands to use
; to control them.
;
; device Pmgr cmd port0 bit signal name
; ----- --------- ------- -----------
; SCC powerCntl P01/sccOn *SCC_CNTL
; external port powerCntl P04/serOn *SERIAL_POWER
; internal modem powerCntl P03/ModemOn MODEM_PWR
; modemSet P06 *MODEM_PWROUT
;
; Additionally for the internal modem, MODEM_RESET (a Orca/via2 signal) must be
; manipulated by changing it from an input to and output to de-assert reset.
;
; Powering on the SCC and the external ports only involves sending the correct power
; manager commands. Powering on the internal modem involves some timing delays and a
; specific sequence of commands.
;
; To power the SCC and external ports:
; turn on SCC
; turn on external line drivers
;
; To power the internal modem:
; clear MODEM_RESET
; turn on +5V and -5V to modem (MODEM_PWROUT)
; ... wait >2ms to allow +5V and -5V to settle
; set MODEM_RESET
; enable the modem (*MODEM_PWR)
; wait >5ms to allow reset time
; clear MODEM_RESET
;
;————————————————————————————————————————————————————————————————————————————————————————
StdModemOn
bclr.b #7,([VIA2],vBufB) ; clear modem-reset before turning on power
bsr.s TurnModemPowerOn ; turn on power
moveq.l #3,d0 ; delay 3 msec (50% margin)
bsr.s DelayNMsec ; ... wait for +5v and -5V to ramp
bset.b #7,([VIA2],vBufB) ; set reset before enabling modem
bsr EnableModem ; enable modem
moveq.l #8,d0 ; delay 8 msec
bsr.s DelayNMsec ; ... for reset pulse
bclr.b #7,([VIA2],vBufB) ; clear modem-reset
; enable modem sound interrupt
move.l ([PmgrBase],MdmSndVect),jModemSnd; install in Level 1 VIA1 dispatch table
move.b #((1<<ifIRQ)+\
(1<<ifCB2)),([VIA],vIER) ; enable modem sound interrupt
moveq.l #0,d0 ; set CCR, turn on scc power on return
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: StdModemOff
;
; Input: a0.l = ptr to powermanager pb + 4 byte general data buffer
; d1.b = modem status bits from power manager
;
; Outputs: none
;
; Trashes: d0
;
; Function: Power off the internal dartanian modem
;
;————————————————————————————————————————————————————————————————————————————————————————
StdModemOff
move.b #(1<<ifCB2),([VIA],vIER) ; disable the modem sound interrupt <t28>
bsr.s TurnOffModemSoundSelect ; turn off modem sound if needed
bsr.s DisableModem ; disable modem
move.l #512,d0 ; Delay 512ms for modem to save some of its state
bsr.s DelayNMsec ; ... wait for +5v and -5V to ramp
bsr.s TurnModemPowerOff ; power off modem
moveq.l #8,d0 ; delay 8 msec
bsr.s DelayNMsec ; ... wait for power ramp down
moveq.l #0,d0 ; set CCR, turn off scc power on return
rts ; <H45>
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: StdModemType
;
; Input:
;
; Outputs: d0.l has the modem Type
;
; Trashes: d0
;
; Function: Returns type of modem installed in TIM Modem
;
;————————————————————————————————————————————————————————————————————————————————————————
StdModemType
moveq.l #ModemTypeSerial,d0 ; serial modem on TIM
rts
ENDIF ; {hasPwrControls}
;••••••••••••••••••••••••••••••••••••••• CommsPowerTables •••••••••••••••••••••••••••••••••••••••• <K12>
;————————————————————————————————————————————————————————————————————————————————————————
; Comms Power Table
;
; Tables of offsets to low level hardware dependent routines which are used for
; powering on and off the various communication ports, be they serial, modem, or Ethernet.
;————————————————————————————————————————————————————————————————————————————————————————
ALIGN 4
DC.L PrimsTypePtr ; flags
DC.L (CommPowerTableEnd-CommsPowerTable) ; number of entries
CommsPowerTable
@PwrOn DC.L PortBOn-CommsPowerTable ; B serial
DC.L PortAOn-CommsPowerTable ; A serial
DC.L PortCOn-CommsPowerTable ; C serial (internal modem)
DC.L 0 ; no ethernet
@PwrOff DC.L PortBOff-CommsPowerTable ; B serial
DC.L PortAOff-CommsPowerTable ; A serial
DC.L PortCOff-CommsPowerTable ; C serial (internal modem)
DC.L 0 ; no ethernet
CommPowerTableEnd
with ModemTblRec
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; PortAOn - setup for port A use
;
;
; Input : d0 = bit 0: 0 = use internal modem, 1 = ignore internal modem
;
PortAOn
@savedregs reg d0-d3/a0-a2 ;
movem.l @savedregs,-(sp)
move.l d0,d2 ; d2 = indicator bits
move.l PmgrBase,a2 ; Get pmgr locals
bset #SerPortAPwr,PmgrFlags2(a2); set port a powered
; Check whether we should bypass the modem check
bclr.l #BypassModem,d0 ; set = ignore modem
bne.s @powerScc ; use the external ports
; check modem type
LoadTbl ModemTblPtr,a2,a0
beq.s @powerScc ; <K14>
JsrPrimTbl GetModemType,a0
cmpi.b #ModemTypeSerial,d0 ; is this a serial modem ?
bne.s @powerScc ; power on external port
; Modem is installed - read extended PRAM to see if modem should be powered on
MOVE.L #(1<<16)+(PmgrStatusFlags<<0),D0 ;
ADD.B PRAMBase(a2),D0 ; read the Power Manager flag byte
suba.w #2,sp ; alloc pmgr command pkt
movea.l sp,a0
_ReadXPRAM ; a0 = ptr to buf (writing over cmd word in pkt)
btst.b #UseIntrnlModem,(a0) ; check cdev bit for modem
adda.w #2,sp
bne @powerScc ; set - don't power modem
; Power on the modem
move.b #%00001000,d0 ; power on channel C
_SerialPower
move.b #(1<<ifCB2),([VIA],vIFR) ; clear interrupt flag reg
bset.b #6,([VIA],vPCR) ; change from neg to pos edge int
move.l MdmSndVect(A2),jModemSnd ; install sound on interrupt handler.
; Power on scc
@powerScc
bsr PowerSccOn ; turn on scc
@Done
movem.l (sp)+,@savedregs
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; PortBOn - setup for port B use
;
;
; Input : d0 = bit 0: 0 = use internal modem, 1 = ignore internal modem
;
PortBOn bset #SerPortBPwr, \
([PMgrBase],PmgrFlags2) ; log power state
bsr PowerSccOn ; turn on scc
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; PortCOn - setup for port C use
;
;
; Input : d0 = bit 0: 0 = use internal modem, 1 = ignore internal modem
;
PortCOn bset #SerPortCPwr, \
([PMgrBase],PmgrFlags2) ; log power state
bsr ModemPowerON ; power on modem
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; PortAOff - release port a resources
;
;
PortAOff
@savedregs reg d0-d3/a0-a2 ;
movem.l @savedregs,-(sp)
move.l d0,d2 ; d2 = indicator bits
move.l PmgrBase,a2 ; Get pmgr locals
bclr.b #SerPortAPwr,PmgrFlags2(a2); read the Power Manager flag byte
; check modem type
LoadTbl ModemTblPtr,a2,a0
bne.s @powerOffScc ; <K14>
JsrPrimTbl GetModemType,a0
cmpi.b #ModemTypeSerial,d0 ; is this a serial modem ?
bne.s @powerOffScc ; power on external port
; Power off modem
move.b #%10001000,d0 ; power off channel C
_SerialPower
@powerOffScc
bsr HandleABPower ; power off scc if necessary
@Done
movem.l (sp)+,@savedregs
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; PortBOff - release port a resources
;
;
PortBOff bclr.b #SerPortBPwr,\
([PMgrBase],PmgrFlags2) ; read the Power Manager flag byte
bsr HandleABPower
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; PortCOn - setup for port C use
;
;
; Input : d0 = bit 0: 0 = use internal modem, 1 = ignore internal modem
;
PortCOff bclr #SerPortCPwr, \
([PMgrBase],PmgrFlags2) ; log power state
bsr ModemPowerOFF ; power on modem
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; HandleABPower - given the current port usage, adjust power manager power control lines
;
;
HandleABPower
move.l d0,-(sp) ; save working set
move.b ([PMgrBase],PmgrFlags2),d0 ; get a copy of the flags
andi.b #((1<<SerPortAPwr) \ ; see if port A or B
+ (1<<SerPortBPwr)),d0 ; ... is currently in use
bne.s @done ; if non zero, then at least one is in use, exit
bsr PowerSccOff
@Done move.l (sp)+,d0
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; SccOn/PowerSccOff - power control for SCC
;
;
; Power on scc
; power on scc
;
PowerSccOn
pSCCworkreg reg d0-d1/a0-a1
movem.l pSCCworkreg,-(sp)
moveq #0, d0
move.b #(sccOn|serOn), d0 ; load on command
bra.s SendCmd
; power off scc
;
PowerSccOff movem.l pSCCworkreg,-(sp)
moveq #0, d0
move.b #(sccOff|serOff),d0 ; load off command
; bra.s SendCmd
SendCmd
move.l d0, -(sp) ; data to send
move.l sp, -(sp) ; pmRBuffer
move.l 7(SP),-(sp) ; pmSBuffer
move.w #1, -(sp) ; pmLength
move.w #powerCntl,-(sp) ; pmCommand
MOVEA.L sp,a0 ; point to the parameter block
_PMgrOp ; get the modem info
move.l (sp), d0 ; return the status byte
adda.l #pmBlkSize, sp ; pop buffer
movem.l (sp)+,pSCCworkreg
rts
;——————————————————————————————————————————————————————————————————————————————————————— <K12>
; ModemPowerON/ModemPowerOFF - power control for modem slot
;
;
; Power on scc
; Power off modem
ModemPowerON
powerreg reg d0-d2/a0-a2
movem.l powerreg,-(sp) ; save working set
move.l #PowerOnModem,d2 ; load offset into modem primitives table for off
bra.s sendCommand
ModemPowerOFF
movem.l powerreg,-(sp) ; save working set
move.l #PowerOffModem,d2 ; load offset into modem primitives table for off
; bra.s sendCommand
sendCommand move.l PmgrBase,a2 ; Get pmgr locals
move.l vPMgrPrimitives(a2),d0 ; IF NoPrimitives THEN
beq.s @Done ; Exit
movea.l d0,a2 ; get pointer to primitives
move.l ModemTblPtr(a2),d0 ; get offset to ModemTblPtr
beq.s @Done ; Exit
move.l d0,-(sp)
bsr.l ModemStatusRT
move.l d0,d1 ; setup modem status for primitive routines
move.l (sp)+,d0
lea (a2,d0.L),a2 ; get pointer to ModemTblPtr
move.l (a2,d2.L),d0 ; load offset to routine
suba.w #pmBlkSize,sp ; alloc pmgr command pkt
lea pmData(sp),a0 ; get addr of buffer
move.l a0,pmRBuffer(sp) ; set ptr to rcv buffer
move.l a0,pmSBuffer(sp) ; set same ptr to xmit buffer (it's expected or error)
move.l sp,a0
jsr (a2,d0.L) ; Run the routine
adda.w #pmBlkSize,sp ; pop power mgr pkt
@Done
movem.l (sp)+,powerreg ; |
rts ; V
endwith ; {ModemTblRec}
END