supermario/base/SuperMarioProj.1994-02-09/OS/PowerMgr/PowerMgr.a
2019-06-29 23:17:50 +08:00

6210 lines
234 KiB
Plaintext
Raw 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: PowerMgr.a
;
; Contains: 680x0 Interface to the Power Manager.
;
; Written by: Mike Hanlon
; Remangled by Portable Terror Squad
;
; Copyright: © 1986-1993 by Apple Computer, Inc. All rights reserved.
;
; This file is used in these builds: ROM
;
; Change History (most recent first):
;
; <SM10> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines.
; <SM9> 9/1/93 SKH Rolled in from Horror. The old supermario copy of PowerMgr was
; hopelessly out of date, this is an almost straight copy of the Horror
; version.
; <H97> 6/24/93 SWC Clear the disable hard disk spindown flag before calling the
; spindown routine so that the hard disk really does get turned
; off.
; <H96> 6/22/93 SWC Fixed a bug that causes a crash when getting ADB packets (when a
; timeout occurred, it was jumping to the wrong label).
; <H95> 6/21/93 SWC Changed the bit ordering in the modem info selectors and munged
; the SetWakeupTimerEnable into that mess. Get/SetWakeupTimer now
; take a record containing the wakeup time and an enable flag.
; <H94> 6/16/93 SWC The polarity of the hasInternalModem bit in the modem info
; selector was backwards, mainly because the PRAM bit,
; UseIntrnlModem, is set to 1 when using an EXTERNAL modem. Added
; a wakeup on ring bit to the modem info selector. Added a new
; selector to set/clear the wakeup on ring bit. Changed the
; default SCSI Disk Mode address from 1 to 2 so it doesn't
; conflict with the ID of a built-in hard disk in a DuoDock.
; <H93> 6/2/93 SWC Rolled in the modem type entry in the PowerDispatch hook from
; Excelsior. Added the modem type to the modem info selector on
; the public dispatch. Copied the public dispatch vector table
; into RAM.
; <H92> 6/1/93 SWC Only run the reduced speed routines if that feature is supported
; on a particular machine. Filled in the FactoryDisp entry in the
; PowerDispatch table wth a stub so that the RAM-based table gets
; built correctly.
; <H91> 5/31/93 RLE change set/getmachineid to set/getmachineattr (this way PG&E
; won't need to be updated for each and every new machine)
; <H90> 5/28/93 SWC Moved the absolute battery voltage from private to public
; dispatch. Added several new selectors to the public dispatch.
; <H89> 5/5/93 SWC Moved RunHardDiskQueue into the hard disk spindown routine so
; that it will only be called when the hard disk will really be
; spun down. Fixed a bug in SelectIntModem: it was always
; selecting the external modem.
; <H88> 5/4/93 SWC Allocated a buffer for reading/writing PRAM since the old buffer
; (a PMgr command parameter block) isn't available anymore. Always
; clear the NTSC low-mem so we'll get square corners on the main
; screen and menu bar.
; <H87> 5/4/93 SWC Made sure HardDiskQInstall/Remove return zero if no error.
; <H86> 5/4/93 SWC Added include of PowerMgrDispatchEqu.a. Added code to
; SetProcessorSpeed to allow for dynamically switching the
; processor speed on machines that support this feature.
; <H85> 4/23/93 SWC Moved the new PowerDispatch selectors down one in the table
; because #12 was used by the factory and patched in on disk.
; <H84> 4/22/93 RLE for SetMachineID/GetMachineID, force the count to be sent as
; part of the message packet
; <H83> 4/21/93 SWC Changed all routines that reference the primitives tables to
; assume that they exist instead of checking for a nil pointer.
; The initialization code will now hang if a table hasn't been set
; up. Added some more info to the modem info selector, and two new
; selectors to deal with disabling hard disk spindown. Added a new
; selector to _PowerDispatch to return a bitmap of private Power
; Manager features.
; <H82> 4/19/93 SWC Changed the primitives table initialization since there's now a
; vector to it in the ProductInfo table. Added new
; _PowerMgrDispatch selectors. Moved DoSpinDown here from
; SCSIMiscPatch.a.
; <H81> 4/16/93 SWC Pass the pointer to the queue element into the hdProc in
; RunHardDiskQueue
; <H80> 4/15/93 SWC Added in support for the public Power Manager interface trap,
; PowerMgrDisp ($A09E).
; <H79> 4/14/93 RLE add commands to set and get cutoff voltage
; <H78> 3/29/93 RLE add SetMachineID/GetMachineID commands to provide a mechanism to
; inform microcontroller what machine it might be running on; do
; SetMachine command as part of InitPmgrVars, but move part of the
; routine into MorePmgrInit to fit within the patch space
; <H77> 03-11-93 jmp Rolled back to the <H74> rev because we now handle the turning
; on/off the CSC in the CSCPrimaryInit.
; <H76> 3/9/93 RLE in the Power1Control call, add a 50 msec delay after powering up
; the CSC's PNLPWR output to allow it to fully charge
; <H75> 3/5/93 RLE add Power1Cntl and Power1Read to list of pmgr commands not
; entirely supported by PG&E microcontroller
; <H74> 3/3/93 RLE toss <H73> and prepare to do the LCD screen save/restore in the
; driver instead of in the power manager
; <H73> 2/24/93 RLE change InitPmgrPrimitives to support multiple table entries for
; a given decoder type
; <H72> 8/10/92 ag Fixed (aX,aY.w) addressing problem in serial power. aY being
; only size word does not allow for large movement of the
; primitives record (such as into ram).
; <H71> 8/4/92 ag Fixed (aX,aY.w) addressing problem. aY being only size word does
; not allow for large movement of the primitives record (such as
; into ram).
; <H70> 8/3/92 SWC ag/IdleMind wasn't using a long table offset. This causes a
; problem if the table is moved to RAM for patching.
; <H69> 7/31/92 SWC Backed out <H68> and instead just set D0=0 on exit of Wakeup.
; <H68> 7/30/92 SWC Added D0 to the list of SleepRegs so that the original sleep
; type will be returned on exit.
; <H67> 7/29/92 SWC Added a new call in the wakeup code to make sure we have the
; appropriate AppleTalk connection selected. This mostly applies
; to a docking environment where available SCC ports may change
; during sleep.
; <H66> 7/16/92 HJR In WakeUp move the SetSupervisorMode to the very end so that we
; can run on the UserStack. Since the interrupt stack is smaller,
; this fixes a problem where PaintBehind overflows the stack doing
; region calls.
; <H65> 7/14/92 ag Initialize the shorted battery alert delay if the charger is
; installed at powerup.
; <H64> 7/13/92 SWC In Wakeup, added a call to SCSIDiskWakeAlert to put up a
; DeepShit alert if the user has a SCSI Disk Mode cable plugged in
; when we wake up from sleep.
; <H63> 7/13/92 HJR Cleaned-up PowerMgrHook a little bit.
; <H62> 7/13/92 ag Rewrote the battery interrupt handler. Added new subhandlers to
; handle the battery shorted interrupt and the changer state
; change interrupt. Added new constants to the primitive
; infotable for delay of shorted battery dialog and delta battery
; warn level when using an external monitor.
; <H61> 7/11/92 ag Changed SecondaryInitDisp to PowerMgrHookDisp. The selector is
; now a general purpose selector with data passed in the upper
; word of d0. Added 3rd level dispatch table for PowerMgrHookDisp.
; Added scsi disk mode handler, and external monitor on handler.
; <H60> 7/11/92 HJR Changed the name of WakeScrnPtr to ScreenRedrawPtr and slightly
; modified the RestoreScreen routine.
; <H59> 7/10/92 ag Added softpower vector support. Created modem primitives, so
; moved all the serial overpatch stuff and part of the serial
; power stuff to PowerMgrPrimitives.a. With the new space in the
; serial power section moved the modem sound int stuff back to
; it's original location.
; <H58> 7/1/92 ag Add new modem commands to the dartexception table. ($71,$79).
; Commented command ($5D) as a general purpose modem command which
; is modem dependent.
; <H57> 7/1/92 SWC Disable level 3 modem interrupts as well as level 1 PMGR
; interrupts on DBLite. Put a line back into InitPMgrVars to clear
; the PMGR interrupt bit in the IFR (this seems to have been lost
; in the course of changes).
; <H56> 6/30/92 HJR Moved ADBReInit earlier in WakeUp so that user will have cursor
; feedback in wake.
; <H55> 6/29/92 GMR Updated a couple of the PMGROp modem cmd/reply counts in the
; tables.
; <H54> 6/26/92 GMR Added another modem command (SetDAAID) to the PmgrOp command
; table.
; <H53> 6/25/92 djw Fixed a bug in SerPowerOff (found by Steve Christensen) where
; the data length was not being set calling the _PmgrOp. The
; result was 5v was not being turned off to the modem.
; <H52> 6/18/92 SWC Setup PMgrOp to use vectors to make patching easier. These are
; now initialized in InitPMgrVars. Also in PMgrOp, don't point to
; the SCC if no PollProc is installed to avoid overflowing the
; stack when AppleTalk is running on port A (lotsa bytes stashed).
; Added a low power warning flag to IdleMind so we can tell that's
; why we're going to sleep.
; <H51> 6/11/92 djw Removed code to post a video warning message from PSecondaryInit
; because it did not take into account video waking from sleep
; case.
; <H50> 6/4/92 SWC Temporarily changed the reply count for the battery info command
; ($6D) until the PG&E code is updated to fix a bug.
; <H49> 6/2/92 SWC Fixed a bug I introduced in <H46>.
; <H48> 6/1/92 HJR Initialized PmgrRec.Charger in InitPmgrVars. Provided support in
; PSecondaryInit for external video warning if no charger
; installed.
; <H47> 5/29/92 SWC When waking up, check if a docking bar was attached that's not
; supposed to be attached during sleep, and if so, put the machine
; back to sleep.
; <H46> 5/28/92 SWC In NewPMgrTrap, A0 was trashed when we checked if we needed to
; delay for a power control command. It isn't anymore.
; <H45> 5/27/92 SWC Converted changes in <H44> into overpatches cuz as written they
; caused code to move (ROMBind problems in system disk patches).
; <H44> 5/20/92 ag Added DartSPI flag code to enable and disable the SPI interface
; depending on the modem connected.
; <H43> 5/19/92 HJR Added new selector, PDimScreens, to PowerDispatch Trap and added
; accompanying routine which powers down video. Changed
; HdDSpinDown to RunIdleRoutines, a more generalized routine.
; <H42> 5/15/92 SWC Added PMGR diagnostics (selector-based) command ($ED) entry to
; send and receive tables. Moved SndWatch, SndWatchPonti to
; PowerManagerPrimitives as yet another primitive, and fixed
; InitPMgrVars to look up the addresses from the primitives table.
; Sound VBLs are no longer installed by secondary init dispatch,
; since the sound VBLs check to make sure that patches are
; installed before calling the sound input primitives. Changed the
; way the PMgrOp exception table is set up to make the search
; faster.
; <H41> 5/12/92 ag Added secondary init dispatch routine for code execution at
; secondary init time. Removed sound primitives check for sound
; vbl code, vbl now installed at secondary init time. All patches
; should be in by then. Added Dart exception table for SPI. Moved
; init of softshutdown vars to secondary init code.
; <H40> 5/8/92 ag Fixed SoundPonti to check expand mem vector before using the
; vector.
; <H39> 5/8/92 ag Added dartanian busy check to NewPmgrTrap.
; <H38> 5/8/92 HJR Added new primitive for refreshing the screen from wake.
; <H37> 5/7/92 ag Added soft shutdown for Dartanian. Rolled in Modem sound
; patches. Added busy check in power manager protocal.
; <H36> 5/7/92 SWC Added a check in IdleMind to bail on sleeping if sleep is not
; allowed because of the kind of bar that's attached (avoids a
; dialog). Moved the beginning and end parts of NewPMgrTrap around
; a bit so I could add SCC polling to the delay loop for power
; control commands. Added a new selector to PowerDispatch to
; return a scaled battery level.
; <H35> 4/27/92 ag Added new sound watch to use registers in Ponti to control sound
; power.
; <H34> 4/24/92 HJR Fix some alignment problems.
; <H33> 4/24/92 HJR Added new SndWatchPtch to handle DFAC activity. Changed
; CheckForNewPMgr so the Niagra uses new PMgrTrap. Fixed
; Handle_Element bug where a QueueProc element returning error
; would still cause the machine to sleep.
; <H32> 4/22/92 SWC In GoToSleep, changed the BTST to a BSET to block re-entry into
; the sleep code earlier on in the process, and removed the BSET
; in DreamAway (duplication). Added a call to DockingSleepDenied
; (DockingMgr.a) if someone tries to put the system to sleep when
; connected to a bar that doesn't want that to happen.
; <H31> 4/17/92 SWC Fixed bugs in the power control/status emulation routines that
; sometimes cause the wrong information to be returned.
; <H30> 4/13/92 SWC Changed the table entry for "send DFAC command" to 2 bytes since
; we need to pass a byte for the input source as well so the PMGR
; can switch the MUX. Changed the readBattery command emulation to
; return a scaled battery level instead of maximum since we now
; check for the existance of a battery in the battery monitoring
; routine. Fixed a bug in InitPmgrPrimitives (hysteresis was
; being copied into a byte instead of a word).
; <H29> 3/11/92 SWC In InitPmgrVars, get the address of the power cycle register
; from the primitives table instead of a chain of TestFors.
; Installed a VBL task (for machines that support it) to monitor a
; clamshell switch so we can put the machine to sleep or shut it
; down. In Wakeup, always do an ADBReInit since new cursor stuff
; needs this to handle adding devices across sleep. Renamed
; JawsPwrCycReg to PowerCycleReg since non-Jaws machines use it
; too.
; <H28> 3/9/92 SWC Fixed the receive count for the PMGR soft reset command.
; <H27> 3/3/92 SWC Exported GetLevel for use in the SCSI DiskMode code.
; <H26> 2/26/92 SWC In NewPMgrTrap, fixed register usage and saving relating to
; polling the SCC since some registers aren't setup right, and
; others are getting trashed by the PollProc. Added a 125usec
; delay to the end of NewPMgrTrap on powerCntl calls to give the
; power planes a chance to stabilize.
; <H25> 2/21/92 HJR Cleaned up InitPmgrVars a bit. Fixed Batwatch to utilize to 3
; battery levels instead of 4. Also added sleep hysteresis to
; batwatch. Fixed reentrancy problem with sleep.
; <H24> 2/19/92 SWC Fixed the Wakeup padding (off by 2 bytes).
; <H23> 2/17/92 SWC Added docking checks to see if power cycling and/or sleep are
; allowed when we're connected to certain bars on DBLite.
; <H22> 2/14/92 SWC Added docking support to power control/status emulation on
; DBLite.
; <H21> 2/13/92 SWC Moved an emulated command in the table. Fixed a typo.
; <H20> 2/13/92 SWC Fixed a patch that the assembler had optimized to make 2 bytes
; shorter (I specified BSR.W, I got BSR.S).
; <H19> 2/10/92 SWC Added a new PowerDispatch selector to return the base Power
; Manager PRAM address so our clients won't have to go looking
; thru our globals.
; <H18> 2/7/92 SWC Write out default low/dead battery warning levels if the values
; read aren't valid. Default values now come from the ever popular
; primitives info table.
; <H17> 2/7/92 SWC Modified other places that reference Power Manager PRAM bytes to
; use the base address in the globals. Removed old HcMac code cuz
; it's confusing and more than likely won't be used again.
; <H16> 2/5/92 SWC Fixed a cut and paste boo-boo in <H15>.
; <H15> 2/5/92 SWC Moved a couple of the PMGR battery commands down in the tables
; since they were stomping on a pre-existing command. Changed how
; we get the low battery warning and dead battery levels from
; reading them from PRAM to using a specific command (available
; from the TIM days and carried on by DBLite).
; <H14> 2/4/92 SWC Adjusted padding since some stuff has moved a bit (wreaks havoc
; with patches). Re-wrote the sleep and wakeup code to use
; primitives tables to determine what needs to be done.
; <H13> 2/3/92 HJR Added support for PowerManagerPrimitives. Use PmgrPrim for
; default PRAM base, new IdleMind, and new CPUSpeed. Fixed
; HandleElement improperly aborting when encountering non-zero
; sleep queue return in DemandSleep.
; <H12> 1/28/92 SWC Did a bit of re-ordering in InitPMgrPatch2 to reduce the
; possibility of a race condition in clearing any unexpected PMGR
; interrupts.
; <H11> 1/27/92 SWC Updated NewPMgrTrap's transfer tables for new commands.
; <H10> 1/24/92 SWC Fixed the code to save/restore GSC registers over sleep. The new
; PMgrOp code (for DBLite) now uses only a 32ms timeout instead of
; having both long and short timeouts, so that when PG&E gets
; multiple interrupts we won't time out while waiting for it to
; respond.
; <H9> 1/9/92 SWC Rolled in changes for final chips: removed special case checks
; for PMGR interrupts on CA2 (now on CB1), extend DB-Lite's CPU
; speed code to support 25MHz/33MHz versions plus econo-mode.
; Added _PMgrOp emulation for SCSI and SCC clock control/status to
; the power control/status commands since these functions are now
; handled by the MSC. Save and restore GSC registers in the sleep
; code for DB-Lite.
; <H8> 10/29/91 SWC Cleared the interrupt flag before doing a blind interrupt read
; in InitPMgrPatch to make sure it isn't left in a weird state.
; Did miscellaneous cleanup in NewPMgrTrap. Turn on/off the
; serial driver chips as well as the SCC in SerialPower.
; <H7> 10/22/91 SWC Changed SCC polling in NewPMgrTrap to look at the SCC directly
; instead of using the VIA bit. Changed references to NoVRAMVidRam
; to point to the end of the record since the offsets are
; negative.
; <H6> 9/10/91 SWC Set battery voltage for ReadBattery emulation at maximum for
; now. Fixed the returned byte counts for the set/read sound
; emulated routines.
; <H5> 8/27/91 SWC Fixed the [temporary] jump to OneSecInt so that it instead jumps
; 6 bytes into the routine so the VIA's IFR is not cleared a
; second time. Depending on when one-second and ADB interrupts
; came along, it was possible to lose an ADB interrupt if it
; occurred just before the IFR bit was cleared in OneSecInt.
; <H4> 8/26/91 SWC Added Set Screen Brightness command ($41) to the command tables.
; <H3> 8/22/91 SWC Added in a call to the one-second interrupt handler from the
; PMgrInt. Vectored the send and receive count tables for
; NewPMgrTrap so we can make changes and additions without having
; to roll the ROM.
; <H2> 8/8/91 SWC Added universal PMgrOp code which will run on any Power
; Manager-based system. Universalized PMGR interrupt setup.
; Fixed sleep/wakeup sound chip register saving so Batman-specific
; registers are only saved if we've got a Batman. Added an MSC
; entry to the CPUSpeed routine. Added DB-Lite support to the
; sleep code. Fixed an unpatchable bug in InitPMgrVars that was
; found after TERROR was frozen (it just requires moving an
; instruction down).
; ———————————————————————————————————————————————————————————————————————————————————————
; Pre-HORROR ROM comments begin here.
; ———————————————————————————————————————————————————————————————————————————————————————
; <40> 7/11/91 HJR Call HDSpinDown in sleep if HDSpindownflag is not clear and on
; wakeup move KdbReset before interrupts are enabled. Also added
; SleepHook and WakeUpHook to sleep code, and vectorized ModemSnd
; Routines in PMgrGlobals.
; <39> 7/9/91 HJR Added CPUSpeed to PowerDispatch Trap and set SaveSpeedo to
; appropriate speed in InitPMgrVars.
; <38> 7/7/91 HJR Add some more reset for the progressive power cycling.
; <37> 7/3/91 HJR Fix VM powercycling problem by restoring the VBR if we decide to
; skip power cycling due to character pending on SCC.
; <36> 6/25/91 HJR Updated IdleMind to reset progressive power cycling
; appropriately. Fixed bug in PowerCycling030 and PowerCycling020
; to set AutoInt7 appropriately.
; <35> 6/25/91 ag added hysteresis low power value to power manager globals.
; <34> 6/25/91 HJR Set cursor to a watchcursor when going to sleep and fix a bug in
; IdleDelay where a BGE should have been a BLE.
; <33> 6/24/91 HJR Individually test SlpTimeOut and HDTimeOut for zero in
; InitPmgrVars. Determine whether running on '020 or '030 at
; InitPmgrVar and load appropriate power cycling code. Added
; IdleRead, IdleEnable, and IdleDisable to the list of
; PowerDispatchVectors and rewrote IdleState to use these new
; routines.
; <32> 6/24/91 djw Moved init code for notification mgr record from InstallMsg to
; InitPmgr. Added code to install and remove message in case of a
; bad battery condition interrupt from power mgr. Removed modem
; sound int handler from InitPmgr. Add support to disable posting
; notification messages for low power. Fixed bug in SerPowerOff
; and external ports. Added code to call LAPMgr for status of
; port B.
; <31> 6/12/91 ag changed the default of the network check to sleep.
; <30> 6/12/91 ag added network warning override bit in PmgrFlags.
; <29> 6/11/91 HJR Parameterized progressive power cycling with PwrCycProgGrow and
; PwrCycProgMax in PMgrRec. Fixed bug in Installmsg where stack
; was corrupted if message string was null.
; <28> 6/11/91 djw Fix modem sound support using VIA interrupt handlers.
; <27> 6/9/91 HJR Used new Default equates in InitPMgrVar for Power Cycling. Fixed
; bug in checking whether there has been enough elapsed time
; before power cycling. Added IdleDelay to PowerDispatch in order
; to improve IO performance. Modified the Batman saving and
; restoring from sleep so that the registers are written out in
; appropriate order. Cleared the Sound Latch after restoring from
; sleep to hopefully kill the buzzing sound while waking up.
; <26> 5/31/91 djw Add modem sound interrupt routines and install them in
; _SerialPower
; <25> 5/23/91 HJR Returned to a more universal power cycling scheme. Added include
; for PowerPrivEqu.a. Removed WaitStates sleep queue element since
; problem is now solved in hardware, HOPEFULLY!
; <24> 5/10/91 HJR Removed references of ResetSP since it is now saved in
; PMgrGlobalsRec. Changed PMgrTrap to call PollProc before
; interrupts re-enbled. Correct problem VM/NMI bug by setting and
; restoring NMIvector to the restore code during power cycling.
; <23> 4/29/91 HJR Added semaphor for power-up conditions in power cycling. Made
; sleep more universal by calculating the video-ram space from
; universal instead of using hard-coded addresses.
; <22> 4/23/91 ag switch back to supervisor mode on exit of sleep.
; <21> 4/23/91 ag alerts must be run in user mode! so we moved the restore to
; user mode earlier.
; <20> 4/22/91 ag Fixed missing dereference in data structure.
; <19> 4/16/91 HJR Somebody forgot to add a semicolon to the comment part of their
; line!
; <18> 4/15/91 ag added sound vbl code to turn off power to the sound circuits if
; not in use.
; <17> 4/12/91 ag changed the location of "insleep" flag in the power manager
; locals. Changed name of pram flags to avoid conflict with
; reality sources.
; <16> 4/4/91 ag slight correction to test for null proc.
; <15> 4/4/91 ag fixed bug with sleep queue execution. added check for null proc
; pointer.
; <14> 4/3/91 HJR Restore DFAC state on sleep wakeup
; <13> 4/1/91 HJR Modified the switching from User Mode to Supervisor Mode so that
; interrupts may be enable prior to running the queue out of
; wakeup since .MPP needs them enabled. Save all necessary Batman
; sound registers.
; <12> 3/29/91 ag Removed power manager bus contention check. the protocal has
; been changed to just check for busy and retry. Also changed
; timeout to take the new retry protocal into account (extended
; timeouts).
; <11> 3/19/91 jmp Oops, sombody forgot to put a semicolon in front of a comment.
; <10> 3/19/91 HJR Restore SP during wakeup since JumpintoRom sets it. Changed
; register useage in InitPMgrVars since GetRealProc trashes
; d1/a1-a2.
; <9> 3/18/91 HJR Rolled in sleep changes from Reality. Moved sleep to Ram based
; instead of video for performance improvement. Made sure that
; all access to the Video storage is done when the MMU is off
; because of
; MMU wrap.
; <8> 2/18/91 HJR Added DebugUtil call in IdleMind and GotoSleep to set the
; machine into Supervisor mode so that VM will be happy.
; <7> 1/30/91 HJR Changed PwrCycleCount to be part of PwrMgrVars and initialized
; in InitPwrMgrVars.
; <6> 1/24/91 HJR Cleared the bus prior to entering into power cycling by writing
; a zero to rom space. Also changed the write to the Jaws
; register to a Move.l and hit the waitstate register coming out
; of powercycle.
; <5> 1/24/91 HJR Moved IdleMind from PwrControlPatches.a. Also rewrote
; PowerCycling code for speed improvements and MMU bug fixes.
; <4> 1/22/91 djw Replace SerPowerOn and SerPowerOff in SerialPower trap code to
; work with TIM and the TIM modem.
; <3> 1/15/91 HJR Add WaitSSleepTask and install code to InitPMgrVars
; <2> 12/11/90 HJR Updated to the latest PowerMgr interface.
; <2.2> 6/10/89 SWC Moved InitPmgrVars here from StartInit.a.
; <2.1> 4/13/89 MSH Removed level 3 low power warning.
; <2.0> 4/7/89 MSH Gave battery and environment interrupts new names. PmgrInt now
; uses vectors to dispatch to handlers. Clearing low battery bit
; removes any low power message. CloseATalk saves D2.
; <1.9> 3/31/89 MSH Power off turns off the modem, then the rest of power, then
; calls sleep. CloseATalk rewritten. DOQueue now knows about
; sleepnow. If more than two ADB devices in use then ADBReInit
; called at wake up. A sleepnow hides the cursor. Batterymon
; replaced with SndWatch and made a vbl task.
; <1.8> 3/14/89 MSH CloseAtalk needed to close MPP. Mild warning didn't close XPP.
; At WakeUp restart timers the right way. ReInit Normandy test
; register after sleep. Ignore ENV interrupt.
; <1.7> 3/10/89 MSH PowerOff does a SleepNow
; <1.6> 3/9/89 MSH Forgot to check for any mounted file servers when sleep time
; out.
; <1.5> 3/2/89 MSH Reset keymap when sleep called. Spin down and sleep time outs
; reduced to one value each. Low power warning resources are
; loaded into local memory at init. No low power warning may occur
; before system task gets called once. Some local storage use got
; proper equ names.
; <1.4> 2/8/89 MSH Added high temperature warning support, moved all hard disk and
; sleep time out to systemtask, low power warnings are now four in
; number. The last warning goes to sleep in ten seconds. Sleep now
; has request, demand, and now, the last is for low power
; condition. Before calling the sleep queue a check is made of the
; AppleTalk world and if any servers or other activity is present.
; If so the user is warned and given the option to undo sleep. A7
; is now saved in undisplayed video ram rather than in SERegs
; where it interfered with Macsbug. Make use of charger status
; bits to determine if charger connection state has changed.
; <1.3> 12/14/88 MSH Save and restore RAM wait state register, power off uses jump to
; startboot instead of RESET, kick on timer 1 after sleep.
; <1.2> 11/30/88 MSH Fixed the sound control stuff. Gave time out flags legit name.
; Save and restore speed from stack.
; <1.1> 11/10/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <2.2> 11/1/88 MSH Added a whole bunch of stuff. First, the sound watchdog is in
; and running. If no one hits on the ASC for ten seconds then the
; amplifier power is turned off. Also save and restore the ASC
; control registers at sleep. Second, the battery monitor and low
; power interrupt handler are in place. The user is alerted via
; the background notification manager of entering reserve power
; use, half reserve left, and a quarter of reserve power left. One
; SICN and three STR resources required on system disk. Last, the
; power off code called from the shutdown manager is found here.
; <2.1> 9/29/88 MSH Moved the reading of the charger state and time outs from the
; one second stuff to an interrupt routine. BatteryAlrt handles
; the charger connected state change interrupt from the power
; manager. BatteryMon checks the dirty time out data flag to see
; if it is necessary to update the time outs due to a change to
; them from the battery desk accessory.
; <1.9> 9/12/88 MSH Fixed bug in stack framse usage. One second interrupt now points
; to BatteryMon. BatteryMon first calls the one second interrupt
; then checks the state of the battery charger and the time outs.
; Screen saving no longer allocates memory.
; <1.8> 8/5/88 MSH Made WakeUp vectored. Added sleep q calling code.
; <1.7> 7/19/88 MSH Fixed potential stack error in PMGRInt. Save the state of the
; PMGR interrupt bit from VIA at entry and restore on exit. Also
; do more VIA save and restore at wake up.
; <1.6> 6/24/88 MSH Many revisions: Use pmgr local vars to save clock speed. Check
; for valid pmgr vars pointer before using it. Went back to
; original busy test of pmgr chip. Sleep command now has signature
; word sent with command. Removed InitIWM call, didn't actually do
; anything anyway. Temporarily removed call to ADBreInit and added
; kludge to keep old power managers auto polling after sleep.
; <1.5> 6/15/88 MSH Removed one too many SWAPs from PmgrDone. Also changed the test
; for pmgr ready to only use the upper half of the port.
; <1.4> 5/23/88 MSH Trashing speed code saved in upper half of D3 with a MOVEQ.
; <1.3> 5/19/88 BBM Changed two MOVEQs to MOVE.Ls as they were out of range
; <1.2> 4/21/88 MSH Fixed reset vector getting trashed when saving screen.
; <1.1> 3/28/88 BBM Made sure that this code runs at 16M. Blank screen before sleep.
; <1.0> 2/10/88 BBM Adding file for the first time into EASE…
; <C988> 12/21/87 MSH Exported GoToSleep for use by toolevents.
; <C984> 12/16/87 MSH Made start of handshake more tolerant of interrupts.
; <C937> 11/6/87 MSH Mask out PMGR interrupts while in PmgrOp.
; <C930> 11/5/87 MSH Rewrote PmgrInt to use new interrupt interface to PMGR.
; <C916> 10/21/87 MSH More of the same.
; <C915> 10/20/87 MSH Fixed some bugs, turned off interrupts while waiting for pmgr
; ack, and preserved sound bits that may be in VIA port A.
; 9/21/87 MSH New today.
;
BLANKS ON
STRING ASIS
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'PowerPrivEqu.a'
INCLUDE 'PowerMgrDispatchEqu.a'
INCLUDE 'Appletalk.a'
INCLUDE 'LAPEqu.a'
INCLUDE 'Notification.a'
INCLUDE 'IopEqu.a'
INCLUDE 'Egretequ.a'
INCLUDE 'AppleDeskBusPriv.a'
INCLUDE 'MMUEqu.a'
INCLUDE 'IOPrimitiveEqu.a'
INCLUDE 'DockingEqu.a'
INCLUDE 'GestaltEqu.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'Slots.a'
PRINT ON
MACHINE MC68030
MC68881
Unimplement EQU $A89F ; _Unimplemented trap
PowerMngr PROC EXPORT
EXPORT InitPmgrVars
IF hasPwrControls THEN
EXPORT BatInt
EXPORT BatWatch
EXPORT GoToSleep
EXPORT PmgrInt
EXPORT PmgrOp
EXPORT PortableCheck
EXPORT PowerDispatch
EXPORT PowerDownAll
EXPORT SetSupervisorMode
EXPORT WakeUp
EXPORT PmgrTrap
EXPORT IdleUpdate
EXPORT IdleUpdateTrap
EXPORT IdleDelay
EXPORT IdleMind
EXPORT IdleRead
EXPORT IdleEnable
EXPORT IdleDisable
EXPORT IdleState
EXPORT CPUSpeed
EXPORT BasePRAM
EXPORT ScaledBattery
EXPORT PowerMgrHook
EXPORT PDimScreens
EXPORT PMGRrecv
EXPORT PMGRsend
EXPORT PrivateFeatures
EXPORT SecondaryInitproc
EXPORT SerialPower
EXPORT ScsiDiskModeproc
EXPORT ExternaVideoOnproc
EXPORT ModemTypeProc
EXPORT PowerMgrDispatch
EXPORT ModemStatusRT
EXPORT LCDScreenChk
EXPORT GetButtonValues
EXPORT SetHDState
IMPORT CacheFlush ; Dispatch.a
IMPORT DelayNMsec ; PowerMgrPrimitives.a
IMPORT DockingSleepDenied ; DockingMgr.a
IMPORT DockingWakeupDenied ; DockingMgr.a
IMPORT GetHardwareInfo ; Universal.a
IMPORT GetRealProc ; GetReal.a
IMPORT GracefulShutdown ; DockingMgr.a
IMPORT InitQueue ; Queue.a
IMPORT InitSCSIHW ; SCSIMgrInit.a
IMPORT InitWallyWorld ; WallyWorld.a
IMPORT RdXByte ; USTPram.a
IMPORT RSetKMap ; ADBMgr.a
IMPORT SCSIDiskWakeAlert ; SCSIDiskMode.a
IMPORT SetupTimeK ; StartInit.a
IMPORT USTPMgrSendByte ; USTStartUp.a
IMPORT USTPMGRSendCommand ; USTStartUp.a
WITH NMRec,PmgrRec,ADBVars,ADBDeviceEntry
WITH DecoderInfo,DecoderKinds,ProductInfo,VideoInfo,SpBlock
WITH pmCommandRec,SleepqRec,PowerCycleRec,PowerDispRec,PmgrPramRec
WITH PmgrPrimitivesRec,PmgrRoutineRec,PrimInfoTbleRec
WITH IdleMindTblRec,ModemTblRec,HDQueueElement
ENDIF
;••••••••••••••••••••••••••••••••••• Initialization •••••••••••••••••••••••••••••••••••••
;
; Contains:
;
; InitPMgrVars
; SetUpPmgrBase
; SizeTables
; BuildTables
; InitPmgrGlobals
; InitPMgrOp
; DoPmgrCommands
; GetPmgrPRAM
; InstallVBLs
;________________________________________________________________________________________
;________________________________________________________________________________________
;
; Routine: InitPMgrVars
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: allocates and initialized system heap space for the Power Manager's variables,
; installs VBL tasks, etc.
;________________________________________________________________________________________
InitPmgrVars
IF hasPwrControls THEN
TestFor hwCbPwrMgr
BNE.S @DoPMgrInit ; IF pmgr exists THEN intall pmgr stuff
ENDIF ; {hasPwrControls}
LEA @Traps,A1 ; ELSE remove the PmgrOp and Sleep traps
MOVE.W (A1)+,D0 ; Get the Unimplimented trap location
_GetTrapAddress ,newTool ;
@TrapLoop ; WHILE !EndOfList DO {
MOVE.W (A1)+,D0 ; Get the next trap to remove
BEQ.S @exit ;
_SetTrapAddress ,newOS ; Replace the trap with the Unimplimented
BRA.S @TrapLoop ; } LOOP
@exit ;
RTS ; EndELSE
@Traps _Unimplemented
_PmgrOp
_PowerDispatch
_Sleep
DC.W 0
IF hasPwrControls THEN
@DoPMgrInit
@WorkingSet REG D0-D3/A0-A3
MOVEM.L @WorkingSet,-(SP) ; save them regs
BSR SetUpPmgrBase ; set up the PMgr Globas A3 = PmgrGlobals
BSR InitPmgrGlobals ; Initialize our primitives table
BSR InitPMgrOp ; Initialize variables used by PMgrOp
BSR DoPmgrCommands ; Initialize variables through the PMgrOp Call
BSR DoDynamicSpeedChange ; Initialize timing constants for full/reduced speed
BSR GetPmgrPRAM ; Initialize variables through PRam
LEA SleepQHdr(A3),A1 ; init sleep queue
BSR.L InitQueue ; go do it
BSR InstallVBLs ; Install our VBLs
; BSR.L HandleChargeTime ; setup for bulk charge extension
LEA PMGRInt,A0 ; get addr of PMGR interrupt handler
MOVE.L A0,Lvl1DT+(4*ifCB1) ; install as PMGR interrupt receiver
BSR ResetPMGRInts ; clear any pending PMGR interrupts
MOVEM.L (SP)+,@WorkingSet ; restore them regs
RTS
;________________________________________________________________________________________
;
; Routine: SetUpPmgrBase
;
; Inputs: none
;
; Outputs: A3 - Ptr to PmgrGlobals
;
; Trashes: none
;
; Function: Determines the appropriate size of the PmgrGlobals section. It takes as a base
; the PmgrVarSize and walks through the primitives table and sums up there sizes.
;________________________________________________________________________________________
SetUpPmgrBase
@WorkingSet REG D0/A0-A2
MOVEM.L @WorkingSet,-(SP) ; Save them regs
MOVEA.L UnivInfoPtr,A1 ; point to the ProductInfo table
ADDA.L PowerManagerPtr(A1),A1 ; then to the Power Manager's primitives
MOVE.L #PmgrVarSize,D0 ; Start with the Vars Size
BSR SizeTables ; Size the table for new ptr
_NewPtr ,SYS,CLEAR ; allocate space on heap and clear
MOVE.L A0,PmgrBase ; save ptr to it
LEA PmgrVarSize+8(A0),A2 ; get the vPrimitives pointer
MOVE.L A2,vPMgrPrimitives(A0) ; set the vPMgrPrimitives vector
MOVEA.L A2,A0 ; set pointer to beginning of our memory chunk
BSR BuildTable ; build table
BSR.L CacheFlush ; flush caches to be safe
MOVE.L PmgrBase,A3 ; A3 = Ptr to PmgrGlobals
MOVEQ #4/4,D0 ; get the size of the public dispatch table
ADD.W PwrMgrDispVects-2,D0 ;
ASL.L #2,D0 ;
_NewPtr ,SYS ; and allocate space for it in the system heap
BNE.S @GetOut ; -> errors aren't allowed
LEA PwrMgrDispVects-4,A1 ;
MOVE.L (A1)+,D0 ; get the flags and routine count
MOVE.L D0,(A0)+ ; and copy them to RAM
MOVE.L A0,vPublicDispatch(A3) ; save the pointer to the start of the table
MOVE.L A1,D1 ; remember where the table starts in ROM
SUBQ.W #1,D0 ; adjust the count for the DBRA
@CopyPublic MOVE.L (A1)+,(A0) ; copy the routine offset into RAM
ADD.L D1,(A0)+ ; and convert it into an address
DBRA D0,@CopyPublic ; next entry
@GetOut
MOVEM.L (SP)+,@WorkingSet ; Restore them regs
RTS
;________________________________________________________________________________________
;
; Routine: SizeTables
;
; Inputs: A1 - Pointer to top of table
; D0 - Initial size of to be incremented
;
; Outputs: D0 - Incremented Size of Table
;
; Trashes: none
;
; Function: Determines the appropriate size of the tables.
;________________________________________________________________________________________
SizeTables
@WorkingSet REG D1-D3/A1-A2
MOVEM.L @WorkingSet,-(SP) ; save them registers
MOVE.L -8(A1),D1 ; get the flags
ANDI.L #PrimsTypeMask,D1 ; mask out all but last two bits
MOVE.W @EntryType(D1.W*2),D1 ; get the offset to that routine
JMP @EntryType(D1) ; go to that routine
@Table ; Size a Table of Tables
MOVE.L -4(A1),D1 ; setup dbra counter
LSR.L #2,D1 ; arrange it as long word entries
MOVEA.L A1,A2 ; A2 = Beginning rom base of table
ADD.L -4(A1),D0 ; increment for size of table
ADDQ #8,D0 ; account for the size byte and the flags
MOVEQ #0,D2 ; clear the register
@TblLoop ; FOR 0 to MaxNum DO
MOVE.L (A2,D2.L*4),D3 ; get the offset of the first routine
BEQ.S @NilValue ; if offset = 0 then bail
LEA (A2,D3.L),A1 ; get pointer to table
BSR SizeTables ; build the table
@NilValue ADDQ.L #1,D2 ; increment index
CMP.L D1,D2 ; .
BLT.S @TblLoop ; LOOP
BRA.S @Done
@PmgrEx
@Ptr
@Info
ADD.L -4(A1),D0 ; increment the size
ADDI.L #8,D0 ; add in flags and size field
@Done
MOVEM.L (SP)+,@WorkingSet ; restore them registers
RTS
@EntryType
DC.W @Table-@EntryType ; Table of Tables
DC.W @Ptr-@EntryType ; Table of pointers
DC.W @Info-@EntryType ; Table of info
DC.W @PmgrEx-@EntryType ; Table of Power Manager Op Exceptions
DC.W 0 ; Expansion
DC.W 0 ; Expansion
DC.W 0 ; Expansion
DC.W 0 ; Expansion
;________________________________________________________________________________________
;
; Routine: BuildTables
;
; Inputs: A0 - Ptr to location where table is to be built
; A1 - Ptr to ROM table
;
; Outputs: none
;
; Trashes: none
;
; Function: Build all the tables into ram and convert all offsets into pointers for easier
; patching.
;________________________________________________________________________________________
BuildTable
@WorkingSet REG D0-D3/A0-A3
MOVEM.L @WorkingSet,-(SP) ; save them registers
LEA -8(A1),A1 ; get pointer to flags
MOVE.L (A1)+,D0 ; get a copy of the flags
MOVE.L (A1)+,D1 ; get a copy of the size
MOVE.L D0,-8(A0) ; copy out the flags
MOVE.L D1,-4(A0) ; copy out the size
LSR.L #2,D1 ; arrange it as long word entries
ANDI.L #PrimsTypeMask,D0 ; mask out all but last two bits
MOVE.W @EntryType(D0.W*2),D0 ; get the offset to that routine
JMP @EntryType(D0) ; go to that routine
@EntryType
DC.W @Table-@EntryType ; Table of Tables
DC.W @Ptr-@EntryType ; Table of pointers
DC.W @Info-@EntryType ; Table of info
DC.W @PmgrExLoop-@EntryType ; Table of Power Manager Op Exceptions
DC.W 0 ; Expansion
DC.W 0 ; Expansion
DC.W 0 ; Expansion
DC.W 0 ; Expansion
@Table ; Build a Table of Tables
MOVEA.L A0,A3 ; A3 = Beginning ram base of table
MOVEA.L A1,A2 ; A2 = Pointer to rom base of table
MOVEQ #0,D2 ; clear the register
@TblLoop ; FOR 0 to MaxNum DO
ADD.L -4(A1),A0 ; increment ram pointer for size of table
ADDQ.W #8,A0 ; account for the size byte and the flags
@Cont MOVE.L (A2,D2.L*4),D3 ; get the offset of the first routine
BEQ.S @NullVal ; IF offset != 0 THEN
MOVE.L A0,(A3,D2.L*4) ; save pointer to table in table
LEA (A2,D3.L),A1 ; make it a pointer
BSR.S BuildTable ; build the table
ADDQ.L #1,D2 ; increment index
CMP.L D1,D2 ; .
BLT.S @TblLoop ; LOOP
BRA.S @Done
@NullVal ADDQ.L #1,D2 ; increment index
CMP.L D1,D2 ; .
BLT.S @Cont ; LOOP
BRA.S @Done ; and continue on
@Ptr ; Build a Table of Pointers
MOVEQ #0,D2 ; clear the register
@PtrLoop ; FOR 0 to MaxNum DO
MOVE.L (A1,D2.L*4),D3 ; get the offset of the first routine
BEQ.S @NullValue ; IF offset != 0 THEN
ADD.L A1,D3 ; add the offset
@NullValue MOVE.L D3,(A0)+ ; save it in the table
ADDQ.L #1,D2 ; increment index
CMP.L D1,D2 ; .
BLT.S @PtrLoop ; LOOP
BRA.S @Done
@Info ; Build a Table of Info
SUBQ.W #1,D1 ; help out dbra god
@InfoLoop ; FOR 0 to MaxNum DO
MOVE.L (A1)+,(A0)+ ; copy info directly
DBRA D1,@InfoLoop ; LOOP
BRA.S @Done
@PmgrExLoop ; WHILE notDone DO { <K12>
MOVE.W (A1)+,D0 ; get the mask & Exception |
MOVE.W D0,(A0)+ ; copy them directly into Ram Tables v
BEQ.S @Done ; IF mask & Exception == NULL THEN notDone = FALSE
MOVE.L A1,D0 ; get pointer to entry
ADD.L (A1)+,D0 ; calculate the handler's address
MOVE.L D0,(A0)+ ; stuff address in the Ram Tables
BRA.S @PmgrExLoop ; } <K12>
@Done
MOVEM.L (SP)+,@WorkingSet ; restore them registers
RTS
;________________________________________________________________________________________
;
; Routine: InitPmgrGlobals
;
; Inputs: A3 -- Pointer to PmgrVars
;
; Outputs: none.
;
; Trashes: D0/A0-A2
;
; Function: Determines the appropriate size of the tables.
;
;________________________________________________________________________________________
InitPmgrGlobals
; Initialize using InfoTbl
LoadTbl PrimInfoTblPtr,A3,A2
MOVE.B PrimPRAMBase(A2),\
PRAMbase(A3) ; Save value in globals for future reference
MOVEQ #0,D0 ; clear D0
MOVE.B PrimDefHyst(A2),D0 ; get a byte from primitives
MOVE.W D0,Hysteresis(A3) ; set default hysteresis value <H30>
MOVE.W PrimLowWarn(A2),\
LowWarn(A3) ; set default low/dead battery warning levels
MOVE.W PrimPRAMBase(A2),D0 ; get PrimWakeLvl:PrimBatWarnCt in d0 <H62>
EXT.W D0 ; extend the byte value to word (value should be < 127) <H62>
MOVE.W D0,BatteryWarnDly(A3) ; load the dialog delay count for shorted battery int's <H62>
MOVE.W D0,BatteryWarnCnt(A3) ; init battery warning count for shorted battery int's
MOVE.L PowerCycRegAddr(A2),\
PowerCycleReg(A3) ; get the address of the power cycle register
MOVE.B PrimCycRegValue(A2),\
PwrCycRegValue(A3) ; get the value for the power cycle register <K20>
; Initialize using RoutinesTbl
LoadTbl PmgrRoutineTbl,A3,A2
MOVE.L PowerCycPtr(A2),D0
MOVE.L D0,PwrCycProc(A3) ; Save pointer in Globals <H24>
MOVE.L PowerCycResPtr(A2),D0
MOVE.L D0,PwrCycRestore(A3) ; Save pointer in Globals <H24>
MOVE.W #PwrCycWaitTmDef,\
PwrCycWaitTime(A3) ; Set PwrCycWaitTime
MOVE.W #PwrCycSynCntDef,\
PwrCycSyncCount(A3) ; Set number of SyncIdles <27> HJR
MOVE.W #PwrCycleDef,\
PwrCycCounter(A3) ; Set number of power cycle loops. <7> HJR
MOVE.W #PwrCycDelayDef,\
PwrCycDelay(A3) ; Set default delay <27> HJR
MOVE.W #PwrCycProgGrowDef,\
PwrCycProgGrow(A3) ; Set growth increment for power cycling <29> HJR
MOVE.W #PwrCycProgMaxDef,\
PwrCycProgMax(A3) ; Set maximum size for power cycling <29> HJR
MOVE.L #$0FFFFFFF,\
DimmingWaitTime(A3) ; Set Time till we start dimming
MOVE.L EnvIntPtr(A2),D0
MOVE.L D0,vEnvInt(A3) ; save the handler address (or nil if none)
; Initialize the rest
MOVEQ #1,D0
MOVE.L D0,LastAct(A3) ; Init last activity and disk counters <v3.7>
MOVE.L D0,LastHd(A3)
ADDQ.W #nmType,BNmQEntry+qType(A3) ; initialize some notification record fields <H52>
MOVEQ #-1,D0
MOVE.L D0,BNmQEntry+nmSound(A3); Use default sound <H52>
LEA BatInt,A1 ; Set up int handlers <v4.9>
MOVE.L A1,vBatInt(A3)
LEA WakeUp,A1 ; Get Address of WakeUp Routine
MOVE.L A1,WakeVector(A3) ; Save in the Globals
MOVE.L A3,A0 ; Param A0 = Ptr to Pmgr Globals
IF NOT forRomulator THEN ; <SM4>
BSR.L GetRealProc ; Get the physical address of PMgrVars--Warning Destroys Regs D1/A1-A2
ENDIF
MOVE.L A0,PmgrVarPhysPtr(A3) ; Save it off in PwrMgr Globals
MOVE.W #CPUSpeedDisp,D0 ; Find out what speed we are running <39> HJR
_PowerDispatch ; <39> HJR
MOVE.B D0,SaveSpeedo(A3) ; Set saveSpeedo to current speed <39> HJR
LEA DoSpinDown,A1 ; initialize the hard disk spindown vector <H82>
MOVE.L A1,HDvector(A3) ; <H82>
LEA DoHDSpinUP,A1 ; initialize the hard disk spinup vector <H82>
MOVE.L A1,HDSpinUpVector(A3) ; <H82>
BigLEA GracefulShutdown,A1 ; issue shutdown command (AppleEvent) <H59>
MOVE.L A1,vSoftShutdown(A3) ; <H59>
LEA ModemSndOnInt,A1 ; get addr of modem sound interrupt handler <t28> djw
MOVE.L A1,MdmSndVect(A3) ; install PmgrGlobal <40> HJR
ST TOdirtyFlag(A3) ; set time outs to be dirty
BSET.B #ClamshellClosed,\
PmgrFlags(A3) ; initialize the value to be closed <K26>
RTS
;________________________________________________________________________________________
;
; Routine: InitPMgrOp
;
; Inputs: A3 -- pointer to Power Manager's variables
;
; Outputs: none
;
; Trashes: D1/A0-A2
;
; Function: initializes all the variables required by PMgrOp
;________________________________________________________________________________________
InitPMgrOp LEA cmdCounts,A0 ; save pointers to the PMgrOp send/receive count tables <H52>
MOVE.L A0,vSendCountTbl(A3) ; <H52>
LEA replyCounts,A0 ; <H52>
MOVE.L A0,vRecvCountTbl(A3) ; <H52>
BSR.S SetupPMgrOpInterface ; get the PMgrOp exception table <H52>
MOVE.L A1,pmgrOpExceptions(A3) ; and save it <H52>
RTS ; <H52>
;________________________________________________________________________________________
;
; Routine: SetupPMgrOpInterface
;
; Inputs: none
;
; Outputs: D1 -- communications protocol (0=parallel, 2=serial, ...)
; D2 -- 0 = Rom Exception Tables <K15>
; A1 -- pointer to the start of an exception table
;
; Function: returns the protocol type, and a pointer to an exception table for
; handling commands that are either partially or not handled by the
; PMGR microcontroller due to differences in hardware implementations.
;
; Each entry consists of a byte for the "don't care bits" mask,
; a byte for the command number, and a long word for a relative
; offset from the current location to the special handler.
;________________________________________________________________________________________
SetupPMgrOpInterface
MOVE.L PmgrBase,A3 ; get pointer to PmgrBase
MOVEQ #0,D1 ; clear register
MOVE.L A3,D2 ;
ADDQ.L #1,D2 ; IF Power Manager vars valid THEN
BEQ.S @UseROMExceptions ;
LoadTbl PrimInfoTblPtr,A3,A1 ; A0 = Power Managers Info table (RAM)
MOVE.B PrimPMgrCommType(A1),D1 ; D1 = communications protocol type (RAM)
LoadTbl PMgrOpExcepTbl,A3,A1 ; A1 = Power Managers Exception Table (RAM)
RTS ; ELSE
@UseROMExceptions ;
MOVEA.L UnivInfoPtr,A1 ; A1 = ProductInfo table (ROM)
ADDA.L PowerManagerPtr(A1),A1 ; A1 = ROM Power Manager's primitives (ROM)
MOVEA.L A1,A2 ; A2 = A1
ADDA.L PrimInfoTblPtr(A2),A2 ; A2 = Power Managers Info table (ROM)
MOVE.B PrimPMgrCommType(A2),D1 ; D1 = communications protocol type (ROM)
ADDA.L PMgrOpExcepTbl(A1),A1 ; A1 = Power Managers Exception Table (ROM)
RTS ;
;________________________________________________________________________________________
;
; Routine: DoPmgrCommands
;
; Inputs: A3 -- Pointer to PmgrVars
;
; Outputs: none.
;
; Trashes: D0/A0-A1
;
; Function: Determines the appropriate size of the tables.
;
;________________________________________________________________________________________
DoPmgrCommands
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 #PmgrADBoff,-(SP) ; pmCommand = turn off ADB auto poll <H18>
MOVEA.L SP,A0 ; point to the parameter block <H18>
_PMgrOp ; send the command <H18>
LoadTbl PrimInfoTblPtr,A3,A1 ; get pointer to info table
TST.B PrimChargerAttr(A1) ; IF charger attributes THEN
BEQ.S @noChargerAttribs
MOVE.B #ChargerOn,pmData(A0) ; ensure charger turned on <H43>
MOVE.W #1,pmLength(A0) ; pmLength = 1 <H43>
MOVE.W #power1Cntl,pmCommand(A0) ; pmCommand = power 1 control <H43>
_PMgrOp ; send the command <H43>
LoadTbl PrimInfoTblPtr,A3,A1 ; get pointer to info table
MOVE.B PrimChargerAttr(A1),\ ;
pmData(A0) ; stuff the attr <H42>
MOVE.W #1,pmLength(A0) ; pmLength = 1
MOVE.W #setMachineAttr,\ ;
pmCommand(A0) ; pmCommand = send cpu attributes to microcontroller
_PMgrOp ; send the command
@noChargerAttribs
MOVE.W LowWarn(A3),D0 ; get the low warning
MOVE.W D0,pmData(A0) ; stuff the default Pmgr low warning and cutoff <H18>
BEQ.S @NoDefWarnings ; -> no defaults, so trust the PMGR to be right <H30>
MOVE.W #2,pmLength(A0) ; pmLength = 2 <H18>
MOVE.W #setBattWarning,\
pmCommand(A0) ; pmCommand = set low/dead battery levels <H18>
_PMgrOp ; send the command <H18>
@NoDefWarnings
CLR.W pmLength(A0) ; pmLength = 0 <H48>
MOVE.W #batteryRead,pmCommand(A0) ; pmCommand = read Battery State <H48>
_PMgrOp ; send the command <H48>
MOVEA.L pmRBuffer(A0),A0 ; get pointer to receive buffer <H48>
MOVE.B (A0),Charger(A3) ; Initialize charger state <H48>
BTST.B #HasCharger,Charger(A3) ; is the charger inserted <H65>
BEQ.S @exitChrgStateInt ; if not, do nothing <H65>
MOVE.W BatteryWarnDly(A3),\
BatteryWarnCnt(A3) ; load battery warn counter <H65>
@exitChrgStateInt
LEA pmBlkSize(SP),SP ; Remove stack frame <H2>
RTS
;________________________________________________________________________________________
;
; Routine: DoDynamicSpeedChange
;
; Inputs: A3 -- Pointer to PmgrVars
;
; Outputs: none.
;
; Trashes: D0/A0-A1
;
; Function: setup timing constants for full/reduced speed
;
;________________________________________________________________________________________
DoDynamicSpeedChange
LoadTbl PrimInfoTblPtr,A3,A0 ; point to the info table for this machine
MOVEQ #1<<dynamicSpeedChange,\;
D0 ; does this machine support dynamic speed changes?
AND.L PrimPubFeatures(A0),D0 ;
BEQ.S @NotDynamic ; -> no
_FullProcessorSpeed ; find out if we're running at full or reduced speed
EORI.W #1,D0 ; 1=reduced, 0=full
IF EconoBit THEN
LSL.W #EconoBit,D0 ; shift it into the correct position
ENDIF
MOVE.W D0,D3 ; and save it for later
BSR.S @SetProcessorSpeed ; save current timing constants and flip to the opposite speed mode
MOVEA.L VIA,A0 ; save the VIA1 registers,
MOVE.B vIER(A0),-(SP)
MOVE.B vACR(A0),-(SP)
MOVEA.L VIA2,A0 ; save the VIA2 interrupt enables
MOVE.B Rv2IER(A0),-(SP)
BSET #7,(SP)
MOVE.B Rv2SEnb(A0),-(SP)
BSET #7,(SP)
MOVEQ #$7F,D0
MOVE.B D0,Rv2IER(A0) ; and disable the interrupts
MOVE.B D0,Rv2SEnb(A0)
MOVE.L A3,-(SP) ; save A3
BSR.L SetupTimeK ; go calculate the timing constants
MOVEA.L (SP)+,A3 ; restore A3,
MOVEA.L VIA2,A0 ; the VIA2 interrupt enables,
MOVE.B (SP)+,Rv2SEnb(A0)
MOVE.B (SP)+,Rv2IER(A0)
MOVEA.L VIA,A0 ; and the VIA registers
MOVE.B (SP)+,vACR(A0)
MOVE.B (SP)+,vIER(A0)
BSR.S @SetProcessorSpeed ; save the constants for the opposite speed mode, and restore the speed
LEA fullSpeedDBRAs(A3),A1 ; assume we're running at full speed
TST.W D3 ; are we?
BEQ.S @RestoreDBRAs ; -> yep
ADDQ.W #lowSpeedDBRAs-fullSpeedDBRAs,A1
@RestoreDBRAs
MOVE.W (A1)+,TimeDBRA ; restore the original timing constants
MOVE.W (A1)+,TimeSCCDB
MOVE.W (A1)+,TimeSCSIDB
MOVE.W (A1)+,TimeVIADB
@NotDynamic
RTS
@SetProcessorSpeed
LEA fullSpeedDBRAs(A3),A1 ; assume we're running at full speed
TST.W D3 ; are we?
BEQ.S @CopyDBRAs ; -> yep
ADDQ.W #lowSpeedDBRAs-fullSpeedDBRAs,A1
@CopyDBRAs MOVE.W TimeDBRA,(A1)+ ; copy the timing constants from low mem
MOVE.W TimeSCCDB,(A1)+
MOVE.W TimeSCSIDB,(A1)+
MOVE.W TimeVIADB,(A1)+
MOVEQ #1<<EconoBit,D1 ; toggle the full/reduced state
EOR.W D1,D3
MOVE.W D3,D1
JmpRoutine SpeedChangePtr,A3,A0; and go do the switch
;________________________________________________________________________________________
; Routine: GetPmgrPRAM
;
; Inputs: A3 -- Pointer to PmgrVars
;
; Outputs: none.
;
; Trashes: D0/A0
;
; Function: Determines the appropriate size of the tables.
;
;________________________________________________________________________________________
GetPmgrPRAM
LEA -PmgrPramSize(SP),SP ; get a param block
MOVEA.L SP,A0
MOVEQ #PmgrPramSize,D0 ; hi-word = number of PRAM bytes to read <H14>
SWAP D0 ; <H14>
MOVE.B PRAMbase(A3),D0 ; lo-word = base address <H13>
_ReadXPRam ; read in the PMGR PRAM settings
CLR.B NTSC ; clear the NTSC flag (square corners)
TST.W SlpTimeOut(A0) ; are sleep and hard disk timeouts valid? <H14>
BNE.S @skipwrite ; -> yes
MOVE.B #DfltSlpTime,\
SlpTimeOut(A0) ; Init default time outs <v5.6>
MOVE.B #DfltHDTime,HDTimeOut(A0)
MOVEQ #2,D0 ; hi-word = number of PRAM bytes to write <H14>
SWAP D0 ; <H14>
MOVE.B PRAMbase(A3),D0 ; lo-word = base address <H13>
_WriteXPRam ; write out the default sleep and hard disk timeouts
@skipwrite MOVE.B SlpTimeOut(A0),\
SleepTime(A3) ; Init default time outs for sleep <v5.6>
MOVE.B HDTimeOut(A0),HDTime(A3); for hard disk
LEA PmgrPramSize(SP),SP ; kill param block
RTS
;________________________________________________________________________________________
; Routine: InstallVBLs
;
; Inputs: A3 -- Pointer to PmgrVars
;
; Outputs: none.
;
; Trashes: none
;
; Function: Determines the appropriate size of the tables.
;
;________________________________________________________________________________________
InstallVBLs
LoadTbl PmgrRoutineTbl,A3,A1 ; get pointer to Routine Table
; install the battery monitoring VBL task...
MOVE.L BatteryVBLPtr(A1),D0 ; does this machine monitor the battery level? <H42>
BEQ.S @NoBatteryVBL ; -> no, don't install the VBL task <H42>
LEA BatVBLTask+vblCount(A3),\
A0 ; point to the end of the VBL task record <H42>
MOVE.W #BatFreq,(A0) ; vblCount <H42>
MOVE.L D0,-(A0) ; vblAddr <H42>
ADDQ.W #vType,-(A0) ; vblType = vType <H42>
SUBQ.W #vblType-vblink,A0 ; point to the beginning of the record <H42>
_VInstall ; install the task <H42>
@NoBatteryVBL
; install the sound usage monitoring VBL task...
MOVE.L SoundVBLPtr(A1),D0 ; does this machine monitor sound usage? <H42>
BEQ.S @NoSoundVBL ; -> no, don't install the VBL task <H42>
LEA SwVBLTask+vblCount(A3),\
A0 ; point to the end of the VBL task record <H42>
MOVE.W #SndWFreq,(A0) ; vblCount <H42>
MOVE.L D0,-(A0) ; vblAddr <H42>
ADDQ.W #vType,-(A0) ; vblType = vType <H42>
SUBQ.W #vblType-vblink,A0 ; point to the beginning of the record <H42>
_VInstall ; install the task <H42>
@NoSoundVBL
RTS
;•••••••••••••••••••••••••••• End Of Initialization •••••••••••••••••••••••••••••••••••••
;••••••••••••••••••••••••••••• VBL's & Interrupts •••••••••••••••••••••••••••••••••••••••
;
; Contains:
;
; BatWatch
; RemoveMsg
; InstallMsg
; PMGRInt
; BatInt
;________________________________________________________________________________________
;________________________________________________________________________________________
;
; Routine: BatWatch
;
; Inputs: A1 - pointer to VIA1 base
;
; Outputs: none
;
; Trashes: none (D0-D3, A0-A3 are preserved by the interrupt dispatcher)
;
; Function: Monitors the battery for low power conditions, and then alerts the user via
; the Notification Manager. Also updates dirty sleep and hard disk timeouts.
;________________________________________________________________________________________
BatWatch
MOVE.L PmgrBase,A2
LEA BatVBLTask(A2),A0 ; Get pointer to vbl task
MOVE.W #BatFreq,vblCount(A0) ; Do it again
TST.B SysTaskFlag(A2)
BEQ @exit
@didsystask
JsrRoutine GetLevelPtr,A2,A0 ; Read, average, and convert battery level
BNE.S @valid ; into level -1 - 4, branch if data not ready
MOVE.B #-1,LastLevel(A2) ; Reset last level
BRA.S @BatWatchOut
@valid TST.B D0 ; Test for negative current level
BPL.S @positive
@negative BSR RemoveMsg ; Remove old message (if any)
MOVE.B D0,LastLevel(A2) ; Save level
BRA.S @BatWatchOut
@positive BEQ.S @lesser ; Level 0, do nothing
CMP.B #2,D0 ; Level 2, remap to level 1 (last dialog level) <H25>
BNE.S @lpowermode ; <2> … continue with low power stuff <H25>
MOVEQ #1,D0 ; <2> … remap level 2 to level 1 <H25>
@lpowermode TST.B LastLevel(A2) ; If LasLevel was -1 then new message
BMI.S @newmsg
CMP.B LastLevel(A2),D0 ; If NewLevel<=LastLevel then branch
BLS.S @lesser
@newmsg BSR RemoveMsg ; Remove previous level message
BSR InstallMsg ; Install this level message
CLR.B Level4Cnt(A2) ; Clear level 4 count down timer
MOVE.B D0,LastLevel(A2) ; Save level
BRA.S @BatWatchOut
@lesser CMP.B #4,LastLevel(A2) ; If level 4 then inc timer
BNE.S @BatWatchOut
ADD.B #1,Level4Cnt(A2)
@BatWatchOut
LEA BatVBLTask(A2),A0 ; Get pointer to vbl task
MOVE.W #BatFreq,vblCount(A0) ; Do it again
LoadTbl PrimInfoTblPtr,A2,A0 ; Get pointer to info table
TST.B LastLevel(A2) ; Is the level -1? <H25>
BPL.S @Next ; No, try next check <H25>
BCLR #PmgrWakeLvlSet,PmgrFlags(A2) ; Is the semaphor set? <H25>
BEQ.S @FinishUp ; Nope. Then skip and go on <H25>
MOVE.W PrimLowWarn(A0),D0 ; Get low power values <H25>
BRA.S @SetPmgrLvl ; Set level and get on with life <H30>
@Next CMP.B #4,LastLevel(A2) ; Check if we are in level 4 <H25>
BNE.S @FinishUp ; If not, go on <H25>
TST.B Level4Cnt(A2) ; Is it the first time through? <H25>
BNE.S @FinishUp ; If not, go On <H25>
BSET #PmgrWakeLvlSet,PmgrFlags(A2) ; Set the semaphor <H25>
MOVE.W PrimLowWarn(A0),D0 ; Get low power values <H25>
MOVE.B PrimWakeLvl(A0),D0 ; Get wake level values <H25>
@setPmgrLvl
TST.W D0 ; are there valid levels? <H30>
BEQ.S @FinishUp ; -> no, figure the PMGR knows what to do <H30>
SWAP D0 ; set the values in the top of buffer
MOVE.L D0,-(SP) ; Set the parameter in the buffer
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
MOVE.W #2,-(SP) ; pmLength = 0
MOVE.W #setBattWarning,-(SP) ; pmCommand = set Battery warning level
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; send the command
LEA pmBlkSize(SP),SP ; Remove stack frame
@FinishUp TST.B TOdirtyFlag(A2) ; Check for new timeouts <H25>
BEQ.S @exit
CLR.B TOdirtyFlag(A2) ; Clear the dirty flag <H25>
SUB.W #8,SP ; allocate some stack space <H25>
MOVE.L SP,A0 ; set param block <H25>
MOVEQ #PmgrPramSize,D0 ; hi-word = number of PRAM bytes to read <H25>
SWAP D0 ; <H25>
MOVE.B PRAMbase(A2),D0 ; lo-word = base address <H25>
_ReadXPRam
MOVE.B PmgrStatusFlags(A0),SleepFlags(A2) ; Get the sleep flags <H25>
MOVE.W SlpTimeOut(A0),SleepTime(A2) ; Get latest timeouts <H25>
ADD.W #8,SP ; free the buffer <H25>
_IdleUpdateDispatch ;
@exit RTS
;________________________________________________________________________________________
;
; Routine: RemoveMsg
;
; Inputs: A2 - pointer to Power Manager's variables
;
; Outputs: none
;
; Trashes: A0
;
; Function: removes any pending low power warning messages
;________________________________________________________________________________________
RemoveMsg
BTST.B #AvoidLowPMsg,PmgrFlags(A2) ; are low power messages enabled? <t32> djw
BNE.S nomsg ; no - don't do anything <t32> djw
BatIntRemoveMsg
TST.B lpMSGvalid(A2) ; If no messages pending then nothing to remove
beq.s nomsg ; Yes. remove low power message
MOVE.L D0,-(SP)
LEA BNmQEntry(A2),A0
_NMRemove ; Remove low power warning message
MOVE.L (SP)+,D0
CLR.B lpMSGvalid(A2) ; No messages pending
nomsg RTS
;________________________________________________________________________________________
;
; Routine: InstallMsg
;
; Inputs: A2 - pointer to Power Manager's variables
;
; Outputs: none
;
; Trashes: A0
;
; Function: installs a low power warning message if they're allowed
;________________________________________________________________________________________
InstallMsg
BTST.B #AvoidLowPMsg,PmgrFlags(A2) ; are low power messages enabled? <t32> djw
BNE.S @nmproc ; don't post any message <t32> djw
MOVE.L D0,-(SP)
LEA BNmQEntry(A2),A0 ; Create notification entry
LEA @nmproc,A1
MOVE.L A1,nmResp(A0) ; Use empty response routine below
MOVE.L lpSICNHndl(A2),nmIcon(A0) ; Use the icon
MOVE.W D0,D2 ; Copy level into D2
SUBQ.W #1,D2 ; Adjust for range 0 - 3
LSL.W #2,D2 ; Convert to offset
MOVE.L lpSTR0Ptr(A2,D2.W),nmStr(A0) ; Index into messages strings
TST.L nmStr(A0) ; Do we have a string?
BEQ.S @nonminst ; Nope. Get out...
_NMInstall ; Notify user of low power condition
ST lpMSGvalid(A2) ; Message pending <29> HJR
@nonminst MOVE.L (SP)+,D0 ; <29> HJR
@nmproc RTS ; No notification proc now
;________________________________________________________________________________________
;
; Routine: PMGRInt
;
; Inputs: A1 - pointer to VIA1 base
;
; Outputs: none
;
; Trashes: none (D0-D3 and A0-A3 are preserved by the interrupt dispatcher)
;
; Function: This is the Power Manager interrupt handler. It dispatches to the right
; interrupt handler for the type of interrupt received.
;________________________________________________________________________________________
PMGRInt
MOVE.B #(1<<ifIRQ)+(1<<ifCB1),vIFR(A1) ; clear PMGR interrupt
LEA -12(SP),SP ; Create stack frame
MOVE.L SP,A0
ADDQ.L #2,A0 ; point 2 bytes into buffer
MOVEQ #ReadINT,D0 ; PMGR command, get interrupt flags
BSR PMGRrecv
TST.W D0
BNE.S @exit
MOVE.B (A0),D0 ; Flag byte [int/adb]
LSR.B #4,D0 ; interrupt bits were in upper half
MOVE.W @intPriority(D0.W*2),D0 ; get the offset to that routine
JMP @intPriority(D0) ; jump to that routine
@intPriority
DC.W @exit-@intPriority ; 0 0 0 0
DC.W @isADBint-@intPriority ; 0 0 0 1
DC.W @isBATint-@intPriority ; 0 0 1 0
DC.W @isADBint-@intPriority ; 0 0 1 1
DC.W @isEnvInt-@intPriority ; 0 1 0 0
DC.W @isADBint-@intPriority ; 0 1 0 1
DC.W @isBATint-@intPriority ; 0 1 1 0
DC.W @isADBint-@intPriority ; 0 1 1 1
IF BlackBirdDebug THEN ; goes away when BB handles one sec ints for real
DC.W @exit-@intPriority ; 1 0 0 0
ELSE
DC.W @oneSecInt-@intPriority ; 1 0 0 0
ENDIF
DC.W @isADBint-@intPriority ; 1 0 0 1
DC.W @isBATint-@intPriority ; 1 0 1 0
DC.W @isADBint-@intPriority ; 1 0 1 1
IF BlackBirdDebug THEN ; goes away when BB handles one sec ints for real
DC.W @exit-@intPriority ; 1 1 0 0
ELSE
DC.W @oneSecInt-@intPriority ; 1 1 0 0
ENDIF
DC.W @isADBint-@intPriority ; 1 1 0 1
DC.W @isBATint-@intPriority ; 1 1 1 0
DC.W @isADBint-@intPriority ; 1 1 1 1
@oneSecInt LEA 12(SP),SP ; clean up PB on stack
MOVEA.L VIA,A1 ; OneSecInt expects pointer to VIA in A1 <H3>
MOVEA.L Lvl1DT+(4*ifCA2),A0 ; get the address of the one-second interrupt handler <H3>
JMP (A0) ; and call it <H3>
@isEnvInt MOVE.L PMgrBase,A2
MOVE.L vENVInt(A2),D0 ; Check for valid vector
BRA.S @callHandler
@isBATint MOVE.L PMgrBase,A2
MOVE.L vBatInt(A2),D0 ; Check for valid vector
bra.s @callHandler
@isADBint andi.b #$0F,(a0) ; mask off interrupt status bits
move.b 1(a0),-(a0) ; [cmd] [stat] [cmd]
subq.b #2,d1 ; actual count
move.b d1,2(a0) ; [cmd] [stat] [len]
move.l Lvl1DT+8,d0 ; Check for valid vector
@callHandler
beq.s @exit ; no handler, exit
move.l d0,a1
jsr (a1) ; call handler
@exit lea 12(sp),SP ; Done with stack frame
rts
;________________________________________________________________________________________
;
; Routine: BatInt
;
; 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 interrupts that occur because of a change in charger connection
; state, or a shorted battery condition is detected.
;________________________________________________________________________________________
BatInt
moveq.l #0,d2 ; clear reg
move.b 1(a0),d2 ; get battery flags
move.b d2,Charger(a2) ; save charger state
; Charger Change interrupt
btst.l #ChrgState,d2 ; was there a charger int
beq.s @exitChargeState ; procede to next test
btst.l #HasCharger,d2 ; is the charger inserted
beq.s @exitChargeState ; if not, do nothing
move.w BatteryWarnDly(a2),BatteryWarnCnt(a2); load battery warn counter
@exitChargeState
; batter shorted interrupt
btst.l #ShortedBat,d2 ; is there a shorted battery?
beq.s @shortTestexit ; not this time
tst.w BatteryWarnCnt(a2) ; if counter
ble.s @postShortedBatt ; if less than or equal, post message
subq.w #1,BatteryWarnCnt(a2) ; update counter
bra.s @shortTestexit ; exit handler
; Shorted battery condition detected - post notification message
; Remove any pending low power messages and prevent any more from showing up so they
; don't try to remove the bad battery message.
@postShortedBatt
bsr BatIntRemoveMsg ; remove any old message
bset.b #AvoidLowPMsg,PmgrFlags(a2) ; avoid confict with low power messages
lea bbSTR0Ptr(a2),a1 ; get first vectored string
bset.b #BadBatDet,PmgrFlags(a2) ; is this the first bad message?
beq.s @continue
addq.l #4,a1 ; index to second harsher message
bclr.b #BadBatDet,PmgrFlags(a2) ; reset bad battery level for next time
@continue
tst.l (a1) ; does the string exist?
beq.s @shortTestexit ; no string - do not post message
lea BNmQEntry(a2),a0 ; a0 = ptr to notification mgr record
move.l (a1),nmStr(a0) ; set string message
lea @BatResp,a1 ; address of response routine
move.l a1,nmResp(a0) ; set response routine
move.l lpSICNHndl(a2),nmIcon(a0) ; Use the icon
_NMInstall ; notify user of defective battery condition
subq.l #4,sp
movea.l sp,a0 ; a0 = pmgr pkt data buffer
move.b #writePmgrRAM,d0 ; pmgr command
moveq.l #3,d1 ; 3 bytes to send
move.w #$0021,(a0) ; set addr to write to
andi.l #~((1<<ShortedBat)+\
(1<<hasCharger)),d2 ; clear short and charger condition
move.b d2,2(a0) ; set data byte
bsr PmgrSend ; tell pmgr to clear the interrupt
addq.l #4,sp ; free buffer
@shortTestexit
rts ; exit interrupt handler
@BatResp movea.l (sp)+,a1 ; save return addr
movea.l (sp)+,a0 ; get ptr to BNmQEntry
_NMRemove ; remove the bad battery notification
movea.l PmgrBase,a0 ; get ptr to pmgr globals |
bclr.b #AvoidLowPMsg,PmgrFlags(a0) ; allow low power messages again V
jmp (a1) ; return to caller <H62>
;•••••••••••••••••••••••••••• End of VBL's & Ints •••••••••••••••••••••••••••••••••••••••
;••••••••••••••••••••••••••••••••••• Traps ••••••••••••••••••••••••••••••••••••••••••••••
;
; Contains:
;
; PowerDispatch
; IdleUpdate (Selector #1)
; IdleDelay (Selector #2)
; IdleMind (Selector #3)
; IdleRead (Selector #4)
; IdleEnable (Selector #5)
; IdleDisable (Selector #6)
; CPUSpeed (Selector #7)
; BasePRAM (Selector #8)
; ScaledBattery (Selector #9)
; PowerMgrHook (Selector #10)
; SecondaryInitproc
; ScsiDiskModeproc
; ExternaVideoOnproc
; ModemTypeProc
; PDimScreens (Selector #11)
; PrivateFeatures (Selector #13)
; GetButtonValues (Selector #15)
; SetHDState (Selector #16)
;
; PmgrOp
; IdleUpdate
; IdleState
; SerialPower
; Sleep
; SlpQInstall
; SlpQRemove
;________________________________________________________________________________________
;________________________________________________________________________________________
;
; Routine: PowerDispatch (trap $A09F)
;
; Inputs: D0 - selector
;
; Outputs: D0 - selector result, or error code if bad selector
;
; Trashes: varies by selector
;
; Function: This is the Power Manager's private dispatch trap, and provides a variety of
; miscellaneous functions.
;________________________________________________________________________________________
PowerDispatch
WITH PwrDispatchRec
MOVE.L PmgrBase,A0 ; Get pointer to globals
LoadTbl PwrDispatchTbl,A0,A0 ; Get pointer to Table
MOVEQ #0,D1 ; Clear D1
MOVE.W D0,D1 ; Get selector in D1
LSL.W #2,D1 ; Convert selector to bytes
CMP.L PwrDispCount(A0),D1 ; IF Dispatch Out of Range THEN
BHI.S @Error ; Get Out Of Here
TST.L ([A0,D1.L]) ; ELSE Dispatch Non Existent THEN
BEQ.S @Error ; Get Out of Here
JMP ([A0,D1.L]) ; Go do that routine
@Error
MOVEQ #paramErr,D0 ; Abort and return error
RTS
ENDWITH
;________________________________________________________________________________________
;
; Routine: IdleUpdate ($A285) (PowerDispatch selector #1)
;
; Inputs: none
;
; Outputs: D0 - time of last activity, in ticks
;
; Trashes: A1
;
; Function: resets the idle compare time to Ticks unless the idle compare time is
; already pushed out beyond Ticks.
;________________________________________________________________________________________
IdleUpdateTbl
DC.W Exit-IdleUpdateTbl ; $00 => OverallAct <K20>
DC.W UsrAct-IdleUpdateTbl ; $01 => UsrActivity |
DC.W NetAct-IdleUpdateTbl ; $02 => NetActivity v
DC.W HDAct-IdleUpdateTbl ; $03 => HardDriveActivity
TblEnd DC.W 0 ; $04 => padding for now
IdleUpdateTrap
MOVEQ #0,D0 ; clear selector
IdleUpdate
SWAP D0 ; Get our selector
MOVE.W D0,D1 ; Get a copy of the selector
MOVE.W SR,-(SP) ; No ints at this time
OR.W #HiIntMask,SR
MOVE.L PmgrBase,A1 ; get pmgr local
MOVE.L LastAct(A1),D0 ; If LastAct > Ticks then branch
CMP.L Ticks,D0
BHI.S @noLastActupdate
MOVE.L Ticks,LastAct(A1) ; reset sleep/idle time
@noLastActupdate
CMP.W #(TblEnd-IdleUpdateTbl)/2,D1 ; IF entry outofbounds THEN
BHI.S Exit ; exit
MOVE.W IdleUpdateTbl(D1.W*2),D1 ; Get the relative offset to the routine.
JMP IdleUpdateTbl(D1.W) ; GOTO the proper routine.
UsrAct MOVE.L LastUsrAct(A1),D0 ; IF LastUsrAct > Ticks THEN
CMP.L Ticks,D0 ; Exit
BHI.S Exit ; ELSE
MOVE.L Ticks,LastUsrAct(A1) ; Update user activity
BRA.S Exit
NetAct MOVE.L LastNetAct(A1),D0 ; IF LastUsrAct > Ticks THEN
CMP.L Ticks,D0 ; Exit
BHI.S Exit ; ELSE
MOVE.L Ticks,LastNetAct(A1) ; Update user activity
BRA.S Exit
HDAct MOVE.L Ticks,LastHd(A1) ; Update user activity
Exit MOVE.L LastAct(A1),D0 ;
MOVE.W (SP)+,SR ; <K20>
RTS
;________________________________________________________________________________________
;
; Routine: IdleDelay (PowerDispatch selector #2)
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0,A1
;
; Function: This routine will delay Idling (Power Cycling) by setting LastAct to some
; future time. This is in particular useful in Reads, and Writes where the
; PwrCycWaitTime might not be enough time for them to function properly.
;________________________________________________________________________________________
IdleDelay MOVE.W SR,-(SP) ; Save the status register
ORI.W #HiIntMask,SR ; Turn off those interrupts
MOVE.L PMgrBase,A1 ; Get the Globals
MOVEQ #0,D0 ; Clear the register
MOVE.W PwrCycDelay(A1),D0 ; Get the time delay used
ADD.L Ticks,D0 ; update it with Ticks
CMP.L LastAct(A1),D0 ; IF LastAct > New One THEN
BLE.S @Done ; Get Out! <34> HJR
MOVE.L D0,LastAct(A1) ; ELSE set new LastAct
@Done MOVE.W (SP)+,SR ; Restore status register
RTS
;________________________________________________________________________________________
;
; Routine: IdleMind (PowerDispatch selector #3)
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: Checks for hard disk time out, sleep time out, idle time out, and low power
; sleep. The first check is for a low power condition, if so then sleep is
; immediately called. The next check is for hard disk spin down time out and
; sleep time out. These time outs may be disabled when on the battery if a
; special bit is set. The last check is for idle time out.
;________________________________________________________________________________________
IdleMind
@savedRegs REG D0-D2/A0-A2
MOVEM.L @savedRegs,-(SP) ; Save some registers
MOVE.L PmgrBase,A2 ; Get pmgr locals
MOVE.W PwrCycSyncCount(A2),D0 ; Get the number of syncIdle before IdleMind
ADDI.W #1,PMgrScratch.SyncCounter(A2) ; Increment scratch counter
CMP.W PMgrScratch.SyncCounter(A2),D0 ; Have we done enough SyncIdles
BLT @CommonOut
CLR.W PMgrScratch.SyncCounter(A2) ; reset counter
LoadTbl IdleMindTblPtr,A2,A1 ; Get pointer to IdleMindTble
ST SysTaskFlag(A2) ; Flag that systemtask has been called
JsrPrimTbl CountDownTimer,A1 ; Check if we are in countdown condition
BNE.S @ForceSleep ; IF CountDownTimer THEN sleep
JsrPrimTbl RunIdleRoutines,A1 ; Get pointer to Check for spin down HD <H43>
MOVE.L LastAct(A2),D0 ; Get LastAct
CMP.L Ticks,D0 ; IF LastAct > Ticks THEN
BGT.S @CommonOut ; exit
JsrPrimTbl SleepTimeOut,A1 ; Get pointer to Check for going to sleep
BNE.S @RequestSlp ; IF SleepTimeOut THEN sleep
JsrPrimTbl CheckIdle,A1 ; Get pointer to Check for going to power cycle
BEQ.S @ClrOut ; IF activity THEN clearout
JsrPrimTbl CalcProgPwrCyc,A1 ; Else calculate progressive count
JsrPrimTbl CyclePower,A1 ; Get pointer to Go Power Cycling
BRA.S @CommonOut ; That's All Folks
@RequestSlp
MOVEQ #SleepRequest,D0 ; Set a sleep request
BRA.S @DoSleep ; Go ajourn
@ForceSleep
MOVEQ #SleepNow,D0 ; Set to force sleep
@DoSleep BTST #dockNoSleep,dockFlags(A2) ; is sleeping allowed (if we're connected to a bar) <H36>
BNE.S @SleepDeny ; -> no, avoid putting up a dialog <H36>
_Sleep ; Go to sleep
@SleepDeny BCLR #LowPowerSleep,PMgrFlags2(A2) ; clear the low power sleep flag <H52>
MOVE.L Ticks,LastAct(A2) ; Waking updates last activity <H36>
@ClrOut
CLR.L PMgrScratch.ProgLastAct(A2) ; Reset progressive power cycling
@CommonOut
MOVEM.L (SP)+,@savedRegs ; Restore registers
RTS
;________________________________________________________________________________________
;
; Routine: IdleRead (PowerDispatch selector #4)
;
; Inputs: none
;
; Outputs: D0 - current CPU speed, in MHz
;
; Trashes: A0
;
; Function: returns the current CPU speed
;________________________________________________________________________________________
IdleRead
MOVE.W SR,-(SP) ; Save the status register
ORI.W #HiIntMask,SR ; Kill those vicious interrupts
MOVE.L PMgrBase,A0 ; Get pmgr locals
MOVEQ #0,D0 ; Clear the register
MOVE.B saveSpeedo(A0),D0 ; return current speed
MOVE.W (SP)+,SR ; restore the status register
RTS
;________________________________________________________________________________________
;
; Routine: IdleEnable (PowerDispatch selector #5)
;
; Inputs: none
;
; Outputs: D0 - idle disable count
;
; Trashes: A0
;
; Function: returns the idle disable flag count
;________________________________________________________________________________________
IdleEnable
MOVE.W SR,-(SP) ; Save the status register
ORI.W #HiIntMask,SR ; Kill those vicious interrupts
MOVEQ #0,D0 ; Clear the register
MOVE.L PMgrBase,A0 ; Get pmgr locals
SUBQ.B #1,IdleFlagCnt(A0) ; pop a level
BPL.S @DontClr ; IF IdleFlagCnt < 0 THEN
CLR.B IdleFlagCnt(A0) ; IdleFlagCnt = 0
@DontClr MOVE.B IdleFlagCnt(A0),D0 ; return idle disable count
MOVE.W (SP)+,SR ; restore the status register
RTS
;________________________________________________________________________________________
;
; Routine: IdleDisable (PowerDispatch selector #6)
;
; Inputs: none
;
; Outputs: D0 - idle disable count
;
; Trashes: A0
;
; Function: returns the idle disable flag count
;________________________________________________________________________________________
IdleDisable
MOVE.W SR,-(SP) ; Save the status register
ORI.W #HiIntMask,SR ; Kill those vicious interrupts
MOVEQ #0,D0 ; Clear the register
MOVE.L PMgrBase,A0 ; Get pgmr locals
ADD.B #1,IdleFlagCnt(A0) ; push a level
MOVE.B IdleFlagCnt(A0),D0 ; return idle disable count
MOVE.W (SP)+,SR ; restore the status register
NoPrimRTS RTS
;________________________________________________________________________________________
;
; Routine: CPUSpeed (PowerDispatch selector #7)
;
; Inputs: none
;
; Outputs: D0 - [maximum CPU speed (high word)][current CPU speed (low word)]
;
; Trashes: A0,A1
;
; Function: returns the maximum and current CPU speeds, in MHz
;________________________________________________________________________________________
CPUSpeed
MOVEA.L PMgrBase,A2 ; get pointer to Power Manager globals
MOVEQ #0,D0 ; assume no speed
JmpRoutine CPUSpeedPtr,A2,A0 ; go do that routine
;________________________________________________________________________________________
;
; Routine: BasePRAM (PowerDispatch selector #8)
;
; Inputs: none
;
; Outputs: D0 - base PRAM address used by the Power Manager
;
; Trashes: A0,A1
;
; Function: returns the base PRAM address that the Power Manager uses for keeping its
; permanent state information
;________________________________________________________________________________________
BasePRAM
MOVEA.L PMgrBase,A2 ; get pointer to Power Manager globals
MOVEQ #0,D0
MOVE.B PRAMbase(A2),D0 ; stuff in the base PRAM address we use
RTS
;________________________________________________________________________________________
;
; Routine: ScaledBattery (PowerDispatch selector #9)
;
; Inputs: none
;
; Outputs: D0 - battery information:
; bits 31: 1=battery installed
; 30: 1=battery is charging
; 29: 1=charger connected
; 23-16: warning level (0-255)
; 7- 0: battery level (0-255)
;
; Trashes: D1-D2, A0-A2
;
; Function: returns battery and warning levels scaled into the range 0-255
;________________________________________________________________________________________
ScaledBattery
MOVEA.L PMgrBase,A2 ; get pointer to Power Manager globals
MOVEQ #0,D0 ; assume no battery info
JmpRoutine ScaledBattPtr,A2,A0 ; go do that routine
;________________________________________________________________________________________
;
; Routine: PowerMgrHook (PowerDispatch selector #10)
;
; Inputs: D0 - [hook selector (high word)][PowerDispatch selector=10 (low word)]
;
; Outputs: varies with selector
;
; Trashes: D1-D2, A0-A2
;
; Function: secondary dispatch selector for various functions
;________________________________________________________________________________________
PowerMgrHook
WITH PMgrHookRec
MOVE.L PmgrBase,A2 ; Get pointer to globals
LoadTbl PmgrHookTbl,A2,A0 ; Get pointer to Table
MOVEQ #0,D1 ; Clear D1
SWAP D0 ; Get selector
MOVE.W D0,D1 ; Get selector in D1
LSL.W #2,D1 ; Convert selector to bytes
CMP.L PmgrHookCount(A0),D1 ; IF Dispatch Out of Range THEN
BHI.S @OutOfRange ; Get Out Of Here
JMP ([A0,D1.L]) ; Go do that routine
@OutOfRange
MOVEQ #paramErr,D0 ; Abort and return error
RTS
ENDWITH
;________________________________________________________________________________________
;
; Routine: SecondaryInitproc (PowerMgrHook selector #0)
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: code to execute at secondary init time
;________________________________________________________________________________________
SecondaryInitproc
BCLR #PmgrShutdownReq,PmgrFlags1(A2) ; clear any pending shutdown requests
BSET #PmgrShutdownEnb,PmgrFlags1(A2) ; enable shutdown requests
MOVEQ #noErr,D0
RTS
;________________________________________________________________________________________
;
; Routine: ScsiDiskModeproc (PowerMgrHook selector #1)
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: code to execute if SCSI Disk Mode was entered
;________________________________________________________________________________________
ScsiDiskModeproc
BSET #7,PmgrFlags(A2)
MOVEQ #noErr,D0
RTS
;________________________________________________________________________________________
;
; Routine: ExternaVideoOnproc (PowerMgrHook selector #2)
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: code to execute if external video is running
;________________________________________________________________________________________
ExternaVideoOnproc
LoadTbl PrimInfoTblPtr,A2,A1 ; Get pointer to primitives table
MOVE.B PrimExtVidCor(A1),D0 ; Get Delta Threshold
ADD.B D0,LowWarn(A2) ; add delta threshold to LowWarn
BSR SetPwrLvlTask ; update the power manager micro
MOVEQ #noErr,D0 ; Indicate no problems
RTS ;
;________________________________________________________________________________________ <K9>
;
; Routine: ModemTypeProc (PowerMgrHook selector #3)
;
; Inputs: none
;
; Outputs: d0.l -- modem type
;
; Trashes: a0
;
; Function: returns modem type constant
;________________________________________________________________________________________
ModemTypeProc
WITH ModemTblRec
bsr.l ModemStatusRT ; d0 has the modem status
btst.l #ModemInstalled,d0 ; is the modem physically installed
beq.s @noModem ; if not set, no modem, exit
move.l PmgrBase,a0 ; Get pointer to globals
moveq.l #ModemTypeUnk,d0 ; assume modem installed of unknown type
LoadTbl ModemTblPtr,a0,a0 ; load the Modem table pointer
beq.s @exit ; yes
JsrPrimTbl GetModemType,A0 ; get modem type
rts
@noModem moveq.l #ModemTypeNone,d0 ; no modem
@exit rts
ENDWITH
;———————————————————————————————————————————————————————————————————————————————————————— <K9>
; Routine: ModemStatus
;
; Inputs: none
; Outputs: d0.b - modem status byte
; Trashes: none
;
; Called by: ModemTypeProc
; Calls: PMgrOp
; Function: return the modem status byte in d0
;————————————————————————————————————————————————————————————————————————————————————————
ModemStatusRT
@workingset reg a0
movem.l @workingset,-(sp)
;
; read power manager's modem bit
;
MOVEQ.L #0,D0 ; clear the result register
CLR.L -(SP) ; allocate a buffer for the result
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength
MOVE.W #modemRead,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; get the modem info
MOVE.B pmData(SP),D0 ; return the status byte
ADDA.L #pmBlkSize, sp ; pop buffer
MOVEA.L (SP)+,A0 ; <K28>
RTS
;________________________________________________________________________________________
;
; Routine: PDimScreens (PowerDispatch selector #11)
;
; Inputs: D0 - high word: 0=power up, 1=power down
;
; Outputs: none
;
; Trashes: A0
;
; Function: sets a flag so that IdleMind handles changing state of screens
;________________________________________________________________________________________
PDimScreens
MOVEA.L PmgrBase,A0 ; get pointer to globals
MOVE SR,D0 ; save the sr
SWAP D0 ; Let get the parameter
ORI #HiIntMask,SR ; Mask Interrupts
BSET #PmgrDimReq,PmgrFlags1(A0) ; set the request
BSET #PmgrDimState,PmgrFlags1(A0) ; assume Power Down state
TST.W D0 ; IF Powering Up THEN
BNE.S @Done ;
BCLR #PmgrDimState,PmgrFlags1(A0) ; set Power Up State
@Done
SWAP D0 ; get saved sr
MOVE D0,SR ; restore sr
MOVEQ #0,D0 ; noErr
RTS ; goodbye
;________________________________________________________________________________________
;
; Routine: PrivateFeatures (PowerDispatch selector #13)
;
; Inputs: none
;
; Outputs: D0: bits 0: 1=extended battery status call is supported by PMGR
; 1: 1=battery ID call is supported by PMGR
; 2: 1=switch AC power on/off call is supported by PMGR
;
; Trashes: A0
;
; Function: Returns a bitmap of private Power Manager features.
;________________________________________________________________________________________
PrivateFeatures
MOVEA.L PMgrBase,A2 ; get pointer to Power Manager globals
LoadTbl PrimInfoTblPtr,A2,A0 ; get pointer to Info
MOVE.L PrimPrivFeatures(A0),D0 ; return the bitmap
RTS
;________________________________________________________________________________________
;
; Routine: GetButtonValues (PowerDispatch selector #15)
;
; Inputs: D0 - high word: 0=Brightness Button, 1=Contrass Button
;
; Outputs: D0 - Normalized value from 0-31
;
; Trashes: A0
;
; Function: Return the current state of the appropriate button
;________________________________________________________________________________________
GetButtonValues
SWAP D0 ; Let get the parameter
MOVE.B D0,-(SP) ; data to send = Brightness or Contrass
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
MOVE.W #1,-(SP) ; pmLength
MOVE.W #readButton,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; turn off the hard disk
LEA pmRBuffer+4(SP),SP ; clean up the stack
MOVEQ #0,D0 ; clear the register
MOVE.B (SP)+,D0 ; get the result value and clean off the stack
RTS
;________________________________________________________________________________________
;
; Routine: SetHDState (PowerDispatch selector #16)
;
; Inputs: D0 - high word: 0=Spin down HD, 1=Spin Up HD
;
; Outputs: none
;
; Trashes: A0
;
; Function: Return the current state of the appropriate button
;________________________________________________________________________________________
SetHDState
SWAP D0 ; Let get the parameter
MOVEA.L PMgrBase,A0 ; Get pointer to the globas
TST.W D0 ;
BEQ.S @DoSpinDown
@DoHDSpinUp
MOVE.L HDSpinUpVector(A0),D0 ; is there a spin up routine?
BEQ.S @Done ; -> no, just exit
MOVEA.L D0,A0 ; yes, call the spinup down routine
JSR (A0)
BRA.S @Done
@DoSpinDown
MOVE.L LastHD(A0),D0 ; is the hard disk spinning?
BEQ.S @Done ; -> no, just exit
MOVE.L HDvector(A0),D0 ; is there a spindown routine?
BEQ.S @Done ; -> no, just exit
MOVEA.L D0,A0 ; yes, call the spindown routine
JSR (A0)
@Done MOVEQ #noErr,D0 ; return no error
RTS ; going home
;________________________________________________________________________________________ <K16>
; |
; Routine: PmgrOp v
;
; Inputs: D1 - trap word
;
; Outputs: D0 - selector result, or error code if bad selector
;
; Trashes: varies by selector
;
; Function: This is the PmgrOp trap, and provides which provide for
; PmgrTrap ($A085)
; IdleUpdate ($A285)
; IdleState ($A485)
; SerialPower ($A685)
;________________________________________________________________________________________
PmgrOp
WITH PMgrOpTblRec
ANDI.L #$00000F00,D1 ; Clear all but the trap modifier bits
LSR.W #7,D1 ; Convert selector to bytes
MOVE.L PmgrBase,A1 ; Get pointer to globals
CMPA.L #-1,A1 ; IF Power Manager Var valid THEN
BEQ.S @UseROMTable ; .
LoadTbl PMgrOpTblPtr,A1,A1 ; Get pointer to Table
CMP.L PMgrOpTblCount(A1),D1 ; IF Trap Out of Range THEN
BHI.S @OutOfRange ; Get Out Of Here
JMP ([A1,D1.L]) ; Do the TRAP
@UseROMTable ; ELSE
MOVEA.L UnivInfoPtr,A1 ; A0 = ProductInfo table (ROM)
ADDA.L PowerManagerPtr(A1),A1 ; A0 = ROM Power Manager's primitives (ROM)
ADDA.L PMgrOpTblPtr(A1),A1 ; A0 = Power Managers PMgrOpTblPtr (ROM)
CMP.L PMgrOpTblCount(A1),D1 ; IF Trap Out of Range THEN
BHI.S @OutOfRange ; Get Out Of Here
MOVE.L (A1,D1.L),D1 ; get offset to the trap
JMP (A1,D1.L) ; Do the TRAP
@OutOfRange
MOVEQ #paramErr,D0 ; Abort and return error
RTS ; <K16>
;________________________________________________________________________________________
;
; Routine: PmgrTrap
;
; Inputs: A0 -- pointer to Power Manager parameter block
; [word] command/reply
; [word] number of bytes to send/receive
; [long] pointer to send buffer
; [long] pointer to receive buffer
;
; Outputs: D0 -- result code: 0 if successful, else error code
; (all other registers are preserved)
;
; Uses: D1 -- byte to send/byte received
; D2 -- timeout value for handshaking
; D3 -- loop counter / miscellaneous
; D4 -- saved copy of parameter block pointer
; D5 -- timeout value
; D6 -- [saved SR][interface model: 0=parallel, 2=serial, ...]
; D7 -- pointer to top of SCC poll stack
; A1 -- pointer to VIA1 base
; A2 -- pointer to VIA2 base
; A3 -- send or receive buffer pointer
; A4 -- saved return addresses (Wait4AckLo, Wait4AckHi)
; A5 -- saved return addresses (SendByte, ReceiveByte)
; A6 -- pointer to SCC channel A data register
;
; Function: This is the Power Manager interface trap ($A085).
;________________________________________________________________________________________
PMack EQU v2PMack
PMreq EQU v2PMreq
PMbuf EQU vBufAH
PMbufDir EQU vDirA
PMgrTrap
pmgrPollRegs REG D3/D4/D5/D6/A0/A1/A2/A4
@numPollRegs EQU 4+4
@savedRegs REG D1-D7/A0-A6
MOVEM.L @savedRegs,-(SP) ; save working registers
BSR SetupPMgrOpInterface ; get the setup information
MOVE.W SR,D6 ; save the entry SR in the upper half of D6
SWAP D6
MOVE.W D1,D6 ; and the interface model in the lower half
MOVEA.L A1,A3 ; save the table pointer
; remember the current PMGR interrupt setting, and then disable PMGR interrupts...
MOVEA.L VIA,A1 ; point to VIA1
MOVEA.L VIA2,A2 ; point to the VIA with the handshake lines
MOVEQ #(1<<ifCB1),D1 ; uses CB1 for IRQ
AND.B vIER(A1),D1 ; mask off the PMGR interrupt enable bit(s)
MOVE.B D1,vIER(A1) ; and disable any that are enabled
BEQ.S @NoPMGRInt ; -> interrupts are currently disabled
BSET #ifIRQ,D1 ; be sure to re-enable them on exit
@NoPMGRInt MOVE.B D1,-(SP)
; set up for SCC polling...
LEA -4*@numPollRegs(SP),SP ; allocate space for registers saved if we call PollProc
MOVE.L SP,D7 ; point to the stack top for our SCC poll stack
MOVEA.L SccRd,A6 ; point to the SCC channel A's data register <H26>
ADDQ.W #aData,A6 ; <H26>
TST.L PollProc ; is a poll proc installed? <H52>
BNE.S @WillPoll ; -> yes <H52>
LEA @NoPollSCC+sccData,A6 ; no, avoid collecting bytes no one will use <H52>
@WillPoll
; run thru the exception table for this machine to see if this command is emulated...
MOVE.L A0,D4 ; save the pointer to the parameter block
MOVE.W pmCommand(A0),D0 ; get the command
TST.L A3 ; IF Exception pointer <> NULL THEN
BEQ.S @NoExceptions ;
LEA -4(A3),A3 ; subtract 4 bytes for the loop
@NextException ; WHILE notDone DO {
ADDQ.W #4,A3 ; skip over the offset to the previous handler
MOVE.B (A3)+,D1 ; get the mask
BEQ.S @NoExceptions ; IF mask = NULL THEN end of list
AND.B D0,D1 ; mask off the bits we care about
CMP.B (A3)+,D1 ; IF this command emulated THEN
BNE.S @NextException ;
MOVEM.L A0-A2,-(SP) ; save state
ORI #HiIntMask,SR ; mask interrupts
TST.L D2 ; IF rom tables THEN <K15>
BNE.S @RamTables ; .
ADDA.L (A3),A3 ; calculate the handler's address
JSR (A3) ; and call the handler
BRA.S @ExceptDone ;
@RamTables
JSR ([A3]) ; call the handler
@ExceptDone
MOVEM.L (SP)+,A0-A2 ; restore state
BEQ @PMgrOpExit ; and exit
@NoExceptions ; }
MOVE.W TimeVIAdb,D5 ; calculate a 32ms timeout value
LSL.W #5,D5
MOVE.W #8*64-1,D3 ; initialize the retry count (8 ms)
MOVE.W (A0)+,D1 ; get the command byte
; wait for /ack to go away in case the PMGR is busy...
@CmdRetry MOVE.W #pmBusyErr,D0 ; assume a timeout
MOVE.W timeVIAdb,D2 ; use a 4 ms timeout value
LSL.W #2,D2
BSR Wait4AckHi ; wait for /ack to go high if it's currently low
BEQ @PMgrOpExit ; -> timed out waiting for initial conditions
IF hasNiagra THEN ; <H39>
IF isUniversal THEN ; <H39>
TestFor NiagraExistsBit ; <H39>
beq @pmgrFree ; call old routine <H39>
ENDIF ; <H39>
@BusyCheck
MOVE.W timeVIAdb,D2 ; Get 1ms timeout value <H39>
LSL.W #4,D2 ; multiply by 16 <H39>
MOVE.B #0,PMBufDir(A2) ; set Port A is input <H39>
@pmgrbusy
CMP.B #$07,PMbuf(A2) ; Get port status <H39>
DBNE D2,@pmgrbusy ; Wait pmgr not busy <H39>
BNE.S @pmgrFree ; if not busy status, continue <H39>
MOVE.L #pmBusyErr,D0 ; Timeout, flag error <H39>
BRA @PMgrOpExit ; Timed out waiting for initial conditions <H39>
@pmgrFree
ENDIF ; <H39>
; send the command byte...
ORI #HiIntMask,SR ; no interrupts while sending the command bytes
BSR SendByte ; send the command byte
BEQ.S @SendCount ; -> success
BSR UnloadPollstack ; unload any SCC data stashed while trying to send the command byte
MOVE.W D5,D2 ; wait for the handshake to abort
SWAP D6
@spin MOVE.W D6,SR ; restore the interrupt level
DBRA D2,@spin
SWAP D6
DBRA D3,@CmdRetry ; try again
BRA @PMgrOpExit ; -> enough retries: just abort
; send the byte count...
;
; As an optimization, commands with fixed length data do not have their
; count byte sent to the PMGR since both sides know what the count is.
@SendCount MOVE.W (A0)+,D3 ; get the byte count
TestFor PMgrNewIntf ; new PMGR?
BEQ.S @SendTheCnt ; -> no, it still sends the count anyway
LEA cmdCounts,A3
MOVEA.L PMgrBase,A4 ; point to the Power Manager's variables <H3>
CMPA.W #-1,A4 ; are they valid yet (-1 if not initialized)? <H3>
BEQ.S @NoSendTbl ; -> no, use the default table <H3>
MOVEA.L vSendCountTbl(A4),A3 ; yes, use the vectored send table <H52>
@NoSendTbl TST.B 0(A3,D1) ; do we need to send the count? <H3>
BPL.S @NoSendCnt ; -> no, both sides know what it is
@SendTheCnt MOVE.W D3,D1 ; use the count passed in
BSR SendByte ; send the byte count to the PMGR
BNE.S @PMgrOpExit ; -> error
; send the command's data bytes to the PMGR...
@NoSendCnt MOVEA.L (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 SendByte ; and send it
@StartSend DBNE D3,@SendData ; -> more bytes to send
BNE.S @PMgrOpExit ; -> error
; the command has been sent, so check if we need to wait for a reply...
SUBQ.W #pmSBuffer-pmCommand,A0 ; point to the start of the parameter block
MOVE.W (A0),D1 ; get the command byte before it gets trashed
LEA replyCounts,A3
MOVEA.L PMgrBase,A4 ; point to the Power Manager's variables <H3>
CMPA.W #-1,A4 ; are they valid yet (-1 if not initialized)? <H3>
BEQ.S @NoRecvTbl ; -> no, use the default table <H3>
MOVEA.L vRecvCountTbl(A4),A3 ; yes, use the vectored receive table <H52>
@NoRecvTbl MOVE.B 0(A3,D1),D3 ; get the reply byte count <H3>
EXT.W D3
MOVE.W D3,pmLength(A0) ; stuff the count in case there's no reply <H31>
BEQ.S @PMgrOpExit ; -> no reply, so we're done
; read in the reply byte...
;
; We don't expect a reply byte except for specific commands.
TestFor PMgrNewIntf ; new PMGR?
BEQ.S @ReadReply ; -> no, it still wants the reply byte anyway
SUBQ.W #1,D3 ; do we need to get a reply byte?
BNE.S @NoReply ; -> nope
@ReadReply BSR ReceiveByte ; get the reply byte
BNE.S @ReplyTO ; -> error
@NoReply MOVE.W D1,(A0)+ ; save the reply byte in the parameter block
; read in the reply byte count...
;
; As an optimization, replies with fixed length data do not have their
; count byte sent by the PMGR since both sides know what the count is.
TestFor PMgrNewIntf ; new PMGR?
BEQ.S @ReadCount ; -> no, it still wants the count anyway
TST.W D3 ; is the PMGR sending us a byte count?
BPL.S @NoReplyCnt ; -> no, we both know what it is
@ReadCount BSR ReceiveByte ; get the count byte
BNE.S @PMgrOpExit ; -> error
MOVE.W D1,D3 ; update the reply data byte count
@NoReplyCnt MOVE.W D3,(A0)+ ; save the byte count in the parameter block
; get the reply's data bytes from the PMGR...
ADDQ.W #pmRBuffer-pmSBuffer,A0
MOVEA.L (A0)+,A3 ; get the pointer to where the reply bytes will go
BRA.S @StartReply
@ReplyData BSR ReceiveByte ; get the next reply data byte
BNE.S @PMgrOpExit ; -> error
MOVE.B D1,(A3)+ ; save the byte in the reply data buffer
@StartReply DBRA D3,@ReplyData ; -> more bytes to get
; special-case the power control command, and add a delay if anything was turned on...
@PMgrOpExit MOVEA.L VIA,A1
MOVEA.L D4,A0 ; restore the pointer to the parameter block <H49>
MOVE.W D0,D4 ; save the result code
BNE.S @NotPC ; -> no point in delaying if the command failed <H46>
CMPI.W #powerCntl,pmCommand(A0); was this a power control command? <H26>
BNE.S @NotPC ; -> nope, really all done <H26>
MOVEA.L pmSBuffer(A0),A2 ; point to the send buffer <H36>
CMPI.B #(1<<pTurnOn),(A2) ; was something being turned on? <H36>
BLS.S @NotPC ; -> nope, no need to wait <H36>
MOVE.W TimeVIAdb,D2 ; wait 125usec for the power planes to stabilize <H36>
LSR.W #3,D2 ; <H36>
@Wait125us TST.B (A1) ; (throttle execution speed with a VIA access) <H36>
BTST #RxCA,-sccData(A6) ; SCC data available? <H36>
BEQ.S @NoSCCData ; <H36>
MOVE.B (A6),-(SP) ; yes, push it on the stack <H36>
@NoSCCData DBRA D2,@Wait125us ; -> keep looping if not <H36>
; check if any SCC bytes were collected so we can send them to the serial driver...
@NotPC BSR UnloadPollstack ; unload any SCC data stashed while interrupts were disabled
LEA 4*@numPollRegs(SP),SP ; de-allocate PollProc saved register frame
; clean everything up...
MOVE.B (SP)+,vIER(A1) ; restore the PMGR interrupt state
SWAP D6
MOVE.W D6,SR
MOVE.W D4,D0 ; restore the result
EXT.L D0 ; set condition codes
MOVEM.L (SP)+,@savedRegs ; restore working registers
RTS
@ReplyTO MOVE.W #pmReplyTOErr,D0 ; timed out waiting for the reply
BRA.S @PMgrOpExit
@NoPollSCC DC.W 0 ; A6 points here if no PollProc to avoid stack overflow <H52>
;________________________________________________________________________________________
;
; Routine: Wait4AckLo
;
; Inputs: D2 -- timeout count
; A1 -- pointer to VIA1 base
; A2 -- pointer to VIA2 base
; A6 -- pointer to SCC channel A data register
;
; Outputs: CCR-- BEQ: /ack has gone low, BNE: timed out
;
; Trashes: D2,A4
;
; Function: waits for the /ack handshake line to go low (may time out)
;________________________________________________________________________________________
Wait4AckLo MOVEA.L (SP)+,A4 ; save the return address
BRA.S @WaitLoop
@CheckSCC TST.B (A1) ; (throttle execution speed with a VIA access)
BTST #RxCA,-sccData(A6) ; SCC data available? <H26>
BEQ.S @WaitLoop ; <H7>
MOVE.B (A6),-(SP) ; yes, push it on the stack <H26>
@WaitLoop BTST.B #PMack,(A2) ; has /ack gone low yet?
DBEQ D2,@CheckSCC ; -> keep looping if not
JMP (A4)
;________________________________________________________________________________________
;
; Routine: Wait4AckHi
;
; Inputs: D2 -- timeout count
; A1 -- pointer to VIA1 base
; A2 -- pointer to VIA2 base
; A6 -- pointer to SCC channel A data register
;
; Outputs: CCR-- BNE: /ack has gone high, BEQ: timed out
;
; Trashes: D2,A4
;
; Function: waits for the /ack handshake line to go high (may time out)
;________________________________________________________________________________________
Wait4AckHi MOVEA.L (SP)+,A4 ; save the return address
BRA.S @WaitLoop
@CheckSCC TST.B (A1) ; (throttle execution speed with a VIA access)
BTST #RxCA,-sccData(A6) ; SCC data available? <H26>
BEQ.S @WaitLoop ; <H7>
MOVE.B (A6),-(SP) ; yes, push it on the stack <H26>
@WaitLoop BTST.B #PMack,(A2) ; has /ack gone high yet?
DBNE D2,@CheckSCC ; -> keep looping if not
JMP (A4)
;________________________________________________________________________________________
;
; Routine: ReceiveByte
;
; Inputs: D6 -- interface type
; 0=parallel
; 2=serial
; A1 -- pointer to VIA1 base
; A2 -- pointer to VIA2 base
; A6 -- pointer to SCC channel A data register
;
; Outputs: D0 -- result code (0 if successful)
; D1 -- byte received
;
; Trashes: D2,A4,A5
;
; Function: handshakes a byte from the PMGR micro
;________________________________________________________________________________________
ReceiveByte MOVE.W D5,D2 ; use the standard timeout value
MOVE.W #pmRecvStartErr,D0 ; assume we'll time out
MOVEA.L (SP)+,A5 ; save the return address <H7>
JMP @ReadByte(D6.W) ; go read a byte
@ReadByte BRA.S @RecvParallel
; BRA.S @RecvSerial
@RecvSerial
ORI.B #%00001100,vACR(A1) ; ***for BlackBird_EVT0 HJR***
BCLR #4,vACR(A1) ; set shift register to shift in under external clock
TST.B vSR(A1) ; read a byte to reset the shifter
BCLR #PMreq,(A2) ; assert /req to start the handshake
BSR.S Wait4AckLo ; wait for /ack to go low
BNE.S SendRcvDone ; -> timed out
BSET #PMreq,(A2) ; de-assert /req since we've seen /ack asserted
MOVE.W #pmRecvEndErr,D0 ; assume we'll time out
MOVE.W D5,D2
BSR.S Wait4AckHi ; wait for /ack to go high
BEQ.S SendRcvDone ; -> timed out
MOVE.B vSR(A1),D1 ; read in the byte
MOVEQ #NoErr,D0 ; success!
BRA.S SendRcvDone
@RecvParallel
MOVE.B #$00,PMBufDir(A2) ; make the data port an input
BSR.S Wait4AckLo ; wait for /ack to go low
BNE.S SendRcvDone ; -> timed out
BCLR #PMreq,(A2) ; assert the /req line
MOVE.B PMbuf(A2),D1 ; read in the byte
MOVE.W #pmRecvEndErr,D0 ; assume we'll time out
FinishHshk MOVE.W D5,D2
BSR.S Wait4AckHi ; wait for /ack to go high
BEQ.S SendRcvDone ; -> timed out
MOVEQ #NoErr,D0 ; success!
SendRcvDone BSET #PMreq,(A2) ; be sure /req is not asserted
JSR DisableBuf(D6.W) ; turn off the data buffer
TST.W D0 ; set the condition codes
JMP (A5) ; <H7>
;________________________________________________________________________________________
;
; Routine: SendByte
;
; Inputs: D1 -- byte to send
; D2 -- timeout count
; D6 -- interface type
; 0=parallel
; 2=serial
; A1 -- pointer to VIA1 base
; A2 -- pointer to VIA2 base
; A6 -- pointer to SCC channel A data register
;
; Outputs: D0 -- result code (0 if successful)
;
; Trashes: D2,A4,A5
;
; Function: handshakes a byte to the PMGR micro
;________________________________________________________________________________________
SendByte MOVE.L D5,D2 ; use the standard timeout value
MOVEA.L (SP)+,A5 ; save the return address <H7>
JSR @SendByte(D6.W) ; send the byte
BCLR #PMreq,(A2) ; assert the /req line
MOVE.W #pmSendStartErr,D0 ; assume we'll time out
BSR Wait4AckLo ; wait for /ack to go low
BNE.S SendRcvDone ; -> timed out
BSET #PMreq,(A2) ; de-assert the /req line
MOVE.W #pmSendEndErr,D0 ; assume we'll time out
BRA.S FinishHshk ; wait for /ack to go high
@SendByte BRA.S @SendParallel ; [0] parallel interface
; BRA.S @SendSerial ; [2] serial interface
@SendSerial
ORI.B #%00011100,vACR(A1) ; ***for BlackBird_EVT0 HJR***
; BSET #4,vACR(A1) ; set shift register to shift out under external clock
MOVE.B D1,vSR(A1) ; write out the byte to the shift register
RTS
@SendParallel
MOVE.B #$FF,PMBufDir(A2) ; make the data port an output
MOVE.B D1,PMBuf(A2) ; and write out the byte
RTS
DisableBuf BRA.S @Buf2Input ; [0] parallel interface
; BRA.S @DisableSR ; [2] serial interface
@DisableSR
ORI.B #%00011100,vACR(A1) ; ***for BlackBird_EVT0 HJR***
; BSET #4,vACR(A1) ; make the shift register shift out
RTS
@Buf2Input MOVE.B #0,PMBufDir(A2) ; switch the data port back to an input
RTS
;________________________________________________________________________________________
;
; Routine: UnloadPollstack
;
; Inputs: D7 -- pointer to top of poll stack
; A1 -- pointer to VIA1 base
; A6 -- pointer to SCC channel A data register
; SP -- pointer to bottom of poll stack
;
; Outputs: D7 -- pointer to top of poll stack
; A1 -- pointer to VIA1 base
; A6 -- pointer to SCC channel A data register
; SP -- pointer to top of poll stack
;
; Trashes: D0,D1,D2,A3,A4,A5
;
; Function: calls the poll proc to unload any bytes stashed from SCC
; port A while interrupts were disabled
;________________________________________________________________________________________
UnloadPollstack
MOVEA.L (SP)+,A4 ; pop the return address
CMPA.L D7,SP ; is there any poll data?
BEQ.S @NoSCCData ; -> no
MOVE.L PollProc,D0 ; is there a poll proc?
BEQ.S @NoPollProc ; -> no
MOVE.L D7,PollStack ; stuff the PollStack
MOVEA.L D7,A3
MOVEM.L pmgrPollRegs,(A3) ; save regs while calling poll proc W/O USING STACK
LEA vBufA(A1),A5 ; point to the register with the SCC WR/REQ bit in VIA 1<H26>
MOVEA.L D0,A3
JSR (A3) ; run the poll proc
MOVEA.L D7,A3
MOVEM.L (A3),pmgrPollRegs ; restore our registers
@NoPollProc MOVEA.L D7,SP ; toss any bytes left on the pollstack <H26>
@NoSCCData JMP (A4)
;_______________________________________________________________________________________
;
; This table is used to determine if the 680x0 needs to send a count byte to the PMGR.
; A positive value means that the count is known by both sides, and so it is not sent.
; A negative value means that the command can send variable amounts of data, so the
; count byte needs to be sent.
;
; Unused commands will be marked as expecting the count to be sent so that commands
; may be added without having to change the ROM.
cmdCounts DC.B -1 ; [$00] -
DC.B -1 ; [$01] -
DC.B -1 ; [$02] -
DC.B -1 ; [$03] -
DC.B -1 ; [$04] -
DC.B -1 ; [$05] -
DC.B -1 ; [$06] -
DC.B -1 ; [$07] -
DC.B -1 ; [$08] -
DC.B -1 ; [$09] -
DC.B -1 ; [$0A] -
DC.B -1 ; [$0B] -
DC.B -1 ; [$0C] -
DC.B -1 ; [$0D] -
DC.B -1 ; [$0E] -
DC.B -1 ; [$0F] -
DC.B 1 ; [$10] Subsystem Power/Clock Control
DC.B 1 ; [$11] Subsystem Power/Clock Control (yet more)
DC.B -1 ; [$12] -
DC.B -1 ; [$13] -
DC.B -1 ; [$14] -
DC.B -1 ; [$15] -
DC.B -1 ; [$16] -
DC.B -1 ; [$17] -
DC.B 0 ; [$18] Read Power/Clock Status
DC.B 0 ; [$19] Read Power/Clock Status (yet more)
DC.B -1 ; [$1A] -
DC.B -1 ; [$1B] -
DC.B -1 ; [$1C] -
DC.B -1 ; [$1D] -
DC.B -1 ; [$1E] -
DC.B 0 ; [$1F] RESERVED FOR MSC/PG&E EMULATION
DC.B -1 ; [$20] Set New Apple Desktop Bus Command
DC.B 0 ; [$21] ADB Autopoll Abort
DC.B 2 ; [$22] ADB Set Keyboard Addresses
DC.B 1 ; [$23] ADB Set Hang Threshold
DC.B 1 ; [$24] ADB Enable/Disable Programmers Key
DC.B -1 ; [$25] -
DC.B -1 ; [$26] -
DC.B -1 ; [$27] -
DC.B 0 ; [$28] ADB Transaction Read
DC.B -1 ; [$29] -
DC.B -1 ; [$2A] -
DC.B -1 ; [$2B] -
DC.B -1 ; [$2C] -
DC.B -1 ; [$2D] -
DC.B -1 ; [$2E] -
DC.B -1 ; [$2F] -
DC.B 4 ; [$30] Set Realtime Clock.
DC.B 20 ; [$31] Write Parameter RAM
DC.B -1 ; [$32] Write Extended Parameter RAM.
DC.B -1 ; [$33] -
DC.B -1 ; [$34] -
DC.B -1 ; [$35] -
DC.B -1 ; [$36] -
DC.B -1 ; [$37] -
DC.B 0 ; [$38] Read Realtime Clock.
DC.B 0 ; [$39] Read Parameter RAM
DC.B 2 ; [$3A] Read Extended Parameter RAM.
DC.B -1 ; [$3B] -
DC.B -1 ; [$3C] -
DC.B -1 ; [$3D] -
DC.B -1 ; [$3E] -
DC.B -1 ; [$3F] -
DC.B 1 ; [$40] Set Screen Contrast
DC.B 1 ; [$41] Set Screen Brightness <H4>
DC.B -1 ; [$42] -
DC.B -1 ; [$43] -
DC.B -1 ; [$44] -
DC.B -1 ; [$45] -
DC.B -1 ; [$46] -
DC.B -1 ; [$47] -
DC.B 0 ; [$48] Read Screen Contrast
DC.B 0 ; [$49] Read Screen Brightness
DC.B -1 ; [$4A] -
DC.B -1 ; [$4B] -
DC.B -1 ; [$4C] -
DC.B -1 ; [$4D] -
DC.B -1 ; [$4E] -
DC.B -1 ; [$4F] -
DC.B 1 ; [$50] Set Internal Modem Control Bits
DC.B 0 ; [$51] Clear FIFOs
DC.B 2 ; [$52] Set FIFO Interrupt Marks
DC.B 2 ; [$53] Set FIFO Sizes
DC.B -1 ; [$54] Write Data to Modem
DC.B 1 ; [$55] Set Data Mode
DC.B 3 ; [$56] Set Flow Control Mode <H55>
DC.B 1 ; [$57] Set DAA control lines <H54>
DC.B 0 ; [$58] Read Internal Modem Status
DC.B 1 ; [$59] Get DAA Identification <H55>
DC.B 0 ; [$5A] Get FIFO Counts
DC.B 0 ; [$5B] Get Maximum FIFO Sizes
DC.B 0 ; [$5C] Read Data From Modem
DC.B -1 ; [$5D] General Purpose modem command (modem dependent) <H58>
DC.B -1 ; [$5E] -
DC.B -1 ; [$5F] -
DC.B 2 ; [$60] Set low power warning and cutoff levels
DC.B -1 ; [$61] -
DC.B -1 ; [$62] -
DC.B -1 ; [$63] -
DC.B -1 ; [$64]
DC.B -1 ; [$65] -
DC.B -1 ; [$66] -
DC.B -1 ; [$67] -
DC.B 0 ; [$68] Read Charger State, Battery Voltage, Temperature
DC.B 0 ; [$69] Read Instantaneous Charger, Battery, Temperature
DC.B 0 ; [$6A] Read low power warning and cutoff levels
DC.B 0 ; [$6B] Read Extended Battery Status
DC.B 0 ; [$6C] Read Battery ID
DC.B 0 ; [$6D] Battery Parameters
DC.B -1 ; [$6E] -
DC.B -1 ; [$6F] -
DC.B 1 ; [$70] Set One-Second Interrupt
DC.B 1 ; [$71] Modem Interrupt Control
DC.B 1 ; [$72] Set Modem Interrupt
DC.B -1 ; [$73] -
DC.B -1 ; [$74] -
DC.B -1 ; [$75] -
DC.B -1 ; [$76] -
DC.B -1 ; [$77] -
DC.B 0 ; [$78] Read Interrupt Flag Register.
DC.B 0 ; [$79] Read Modem Interrupt Data
DC.B -1 ; [$7A] -
DC.B -1 ; [$7B] -
DC.B -1 ; [$7C] -
DC.B -1 ; [$7D] -
DC.B 4 ; [$7E] Enter Shutdown Mode
DC.B 4 ; [$7F] Enter Sleep Mode
DC.B 4 ; [$80] Set Wakeup Timer
DC.B -1 ; [$81] -
DC.B 0 ; [$82] Disable Wakeup Timer
DC.B -1 ; [$83] -
DC.B -1 ; [$84] -
DC.B -1 ; [$85] -
DC.B -1 ; [$86] -
DC.B -1 ; [$87] -
DC.B 0 ; [$88] Read Wakeup Timer
DC.B -1 ; [$89] -
DC.B -1 ; [$8A] -
DC.B -1 ; [$8B] -
DC.B -1 ; [$8C] -
DC.B -1 ; [$8D] -
DC.B -1 ; [$8E] -
DC.B -1 ; [$8F] -
DC.B 1 ; [$90] Set Sound Control Bits
DC.B 2 ; [$91] Set DFAC Control Register
DC.B -1 ; [$92] -
DC.B -1 ; [$93] -
DC.B -1 ; [$94] -
DC.B -1 ; [$95] -
DC.B -1 ; [$96] -
DC.B -1 ; [$97] -
DC.B 0 ; [$98] Read Sound Control Status
DC.B 0 ; [$99] Read DFAC Control Register
DC.B -1 ; [$9A] -
DC.B -1 ; [$9B] -
DC.B -1 ; [$9C] -
DC.B -1 ; [$9D] -
DC.B -1 ; [$9E] -
DC.B -1 ; [$9F] -
DC.B 2 ; [$A0] Write Modem Register
DC.B 2 ; [$A1] Clear Modem Register Bits
DC.B 2 ; [$A2] Set Modem Register Bits
DC.B 4 ; [$A3] Write DSP RAM
DC.B -1 ; [$A4] Set Filter Coefficients
DC.B 0 ; [$A5] Reset Modem
DC.B -1 ; [$A6] -
DC.B -1 ; [$A7] -
DC.B 1 ; [$A8] Read Modem Register
DC.B 1 ; [$A9] Send Break
DC.B 3 ; [$AA] Dial Digit
DC.B 2 ; [$AB] Read DSP RAM
DC.B -1 ; [$AC] -
DC.B -1 ; [$AD] -
DC.B -1 ; [$AE] -
DC.B -1 ; [$AF] -
DC.B -1 ; [$B0] -
DC.B -1 ; [$B1] -
DC.B -1 ; [$B2] -
DC.B -1 ; [$B3] -
DC.B -1 ; [$B4] -
DC.B -1 ; [$B5] -
DC.B -1 ; [$B6] -
DC.B -1 ; [$B7] -
DC.B -1 ; [$B8] -
DC.B -1 ; [$B9] -
DC.B -1 ; [$BA] -
DC.B -1 ; [$BB] -
DC.B -1 ; [$BC] -
DC.B -1 ; [$BD] -
DC.B -1 ; [$BE] -
DC.B -1 ; [$BF] -
DC.B -1 ; [$C0] -
DC.B -1 ; [$C1] -
DC.B -1 ; [$C2] -
DC.B -1 ; [$C3] -
DC.B -1 ; [$C4] -
DC.B -1 ; [$C5] -
DC.B -1 ; [$C6] -
DC.B -1 ; [$C7] -
DC.B -1 ; [$C8] -
DC.B -1 ; [$C9] -
DC.B -1 ; [$CA] -
DC.B -1 ; [$CB] -
DC.B -1 ; [$CC] -
DC.B -1 ; [$CD] -
DC.B -1 ; [$CE] -
DC.B -1 ; [$CF] -
DC.B 0 ; [$D0] Reset CPU
DC.B -1 ; [$D1] -
DC.B -1 ; [$D2] -
DC.B -1 ; [$D3] -
DC.B -1 ; [$D4] -
DC.B -1 ; [$D5] -
DC.B -1 ; [$D6] -
DC.B -1 ; [$D7] -
DC.B 1 ; [$D8] Read A/D Status
DC.B 1 ; [$D9] Read User Input
DC.B -1 ; [$DA] -
DC.B -1 ; [$DB] -
DC.B 0 ; [$DC] read external switches
DC.B 0 ; [$DD] -
DC.B -1 ; [$DE] -
DC.B -1 ; [$DF] -
DC.B -1 ; [$E0] Write to internal PMGR memory
DC.B 4 ; [$E1] Download Flash EEPROM Code
DC.B 0 ; [$E2] Get Flash EEPROM Status
DC.B -1 ; [$E3] -
DC.B -1 ; [$E4] -
DC.B -1 ; [$E5] -
DC.B -1 ; [$E6] -
DC.B -1 ; [$E7] -
DC.B 3 ; [$E8] Read PMGR internal memory
DC.B -1 ; [$E9] -
DC.B 0 ; [$EA] Read PMGR firmware version number
DC.B -1 ; [$EB] -
DC.B 0 ; [$EC] Execute self test
DC.B -1 ; [$ED] PMGR diagnostics (selector-based)
DC.B -1 ; [$EE] -
DC.B 0 ; [$EF] PMGR soft reset
DC.B -1 ; [$F0] -
DC.B -1 ; [$F1] -
DC.B -1 ; [$F2] -
DC.B -1 ; [$F3] -
DC.B -1 ; [$F4] -
DC.B -1 ; [$F5] -
DC.B -1 ; [$F6] -
DC.B -1 ; [$F7] -
DC.B -1 ; [$F8] -
DC.B -1 ; [$F9] -
DC.B -1 ; [$FA] -
DC.B -1 ; [$FB] -
DC.B -1 ; [$FC] -
DC.B -1 ; [$FD] -
DC.B -1 ; [$FE] -
DC.B -1 ; [$FF] -
; This table is used to determine how the 680x0 needs to handle the reply:
;
; =0: no reply should be expected.
; =1: only a reply byte will be sent (this is a special case for a couple of commands)
; <0: a reply is expected and the PMGR will send a count byte.
; >1: a reply is expected and the PMGR will not send a count byte,
; but the count will be (value-1).
;
; Unused commands in the range $x8 to $xF will be marked as expecting a reply (with count)
; so that commands may be added without having to change the ROM.
replyCounts DC.B 0 ; [$00] -
DC.B 0 ; [$01] -
DC.B 0 ; [$02] -
DC.B 0 ; [$03] -
DC.B 0 ; [$04] -
DC.B 0 ; [$05] -
DC.B 0 ; [$06] -
DC.B 0 ; [$07] -
DC.B -1 ; [$08] -
DC.B -1 ; [$09] -
DC.B -1 ; [$0A] -
DC.B -1 ; [$0B] -
DC.B -1 ; [$0C] -
DC.B -1 ; [$0D] -
DC.B -1 ; [$0E] -
DC.B -1 ; [$0F] -
DC.B 0 ; [$10] Subsystem Power/Clock Control
DC.B 0 ; [$11] Subsystem Power/Clock Control (yet more)
DC.B 0 ; [$12] -
DC.B 0 ; [$13] -
DC.B 0 ; [$14] -
DC.B 0 ; [$15] -
DC.B 0 ; [$16] -
DC.B 0 ; [$17] -
DC.B 1+1 ; [$18] Read Power/Clock Status
DC.B 1+1 ; [$19] Read Power/Clock Status (yet more)
DC.B -1 ; [$1A] -
DC.B -1 ; [$1B] -
DC.B -1 ; [$1C] -
DC.B -1 ; [$1D] -
DC.B -1 ; [$1E] -
DC.B 0 ; [$1F] RESERVED FOR MSC/PG&E EMULATION
DC.B 0 ; [$20] Set New Apple Desktop Bus Command
DC.B 0 ; [$21] ADB Autopoll Abort
DC.B 0 ; [$22] ADB Set Keyboard Addresses
DC.B 0 ; [$23] ADB Set Hang Threshold
DC.B 0 ; [$24] ADB Enable/Disable Programmers Key
DC.B 0 ; [$25] -
DC.B 0 ; [$26] -
DC.B 0 ; [$27] -
DC.B -1 ; [$28] ADB Transaction Read
DC.B -1 ; [$29] -
DC.B -1 ; [$2A] -
DC.B -1 ; [$2B] -
DC.B -1 ; [$2C] -
DC.B -1 ; [$2D] -
DC.B -1 ; [$2E] -
DC.B -1 ; [$2F] -
DC.B 0 ; [$30] Set Realtime Clock.
DC.B 0 ; [$31] Write Parameter RAM
DC.B 0 ; [$32] Write Extended Parameter RAM.
DC.B 0 ; [$33] -
DC.B 0 ; [$34] -
DC.B 0 ; [$35] -
DC.B 0 ; [$36] -
DC.B 0 ; [$37] -
DC.B 4+1 ; [$38] Read Realtime Clock.
DC.B 20+1 ; [$39] Read Parameter RAM
DC.B -1 ; [$3A] Read Extended Parameter RAM.
DC.B -1 ; [$3B] -
DC.B -1 ; [$3C] -
DC.B -1 ; [$3D] -
DC.B -1 ; [$3E] -
DC.B -1 ; [$3F] -
DC.B 0 ; [$40] Set Screen Contrast
DC.B 0 ; [$41] Set Screen Brightness <H4>
DC.B 0 ; [$42] -
DC.B 0 ; [$43] -
DC.B 0 ; [$44] -
DC.B 0 ; [$45] -
DC.B 0 ; [$46] -
DC.B 0 ; [$47] -
DC.B 1+1 ; [$48] Read Screen Contrast
DC.B 1+1 ; [$49] Read Screen Brightness
DC.B -1 ; [$4A] -
DC.B -1 ; [$4B] -
DC.B -1 ; [$4C] -
DC.B -1 ; [$4D] -
DC.B -1 ; [$4E] -
DC.B -1 ; [$4F] -
DC.B 0 ; [$50] Set Internal Modem Control Bits
DC.B 0 ; [$51] Clear FIFOs
DC.B 0 ; [$52] Set FIFO Interrupt Marks
DC.B 0 ; [$53] Set FIFO Sizes
DC.B 0 ; [$54] Write Data to Modem
DC.B 0 ; [$55] Set Data Mode
DC.B 0 ; [$56] Set Flow Control Mode
DC.B 0 ; [$57] Set DAA control lines <H54>
DC.B 1+1 ; [$58] Read Internal Modem Status
DC.B 0 ; [$59] Get DAA Identification <H55>
DC.B 2+1 ; [$5A] Get FIFO Counts
DC.B 2+1 ; [$5B] Get Maximum FIFO Sizes
DC.B -1 ; [$5C] Read Data From Modem
DC.B -1 ; [$5D] General Purpose modem command (modem dependent) <H58>
DC.B -1 ; [$5E] -
DC.B -1 ; [$5F] -
DC.B 0 ; [$60] Set low power warning and cutoff levels
DC.B 0 ; [$61] -
DC.B 0 ; [$62] -
DC.B 0 ; [$63] -
DC.B 0 ; [$64] -
DC.B 0 ; [$65] -
DC.B 0 ; [$66] -
DC.B 0 ; [$67] -
DC.B 3+1 ; [$68] Read Charger State, Battery Voltage, Temperature
DC.B 3+1 ; [$69] Read Instantaneous Charger, Battery, Temperature
DC.B 2+1 ; [$6A] Read low power warning and cutoff levels
DC.B 8+1 ; [$6B] Read Extended Battery Status
DC.B -1 ; [$6C] Read Battery ID
DC.B -1 ;10+1 ; [$6D] Battery Parameters
DC.B -1 ; [$6E] -
DC.B -1 ; [$6F] -
DC.B 0 ; [$70] Set One-Second Interrupt
DC.B 0 ; [$71] Modem Interrupt Control
DC.B 0 ; [$72] Set Modem Interrupt
DC.B 0 ; [$73] -
DC.B 0 ; [$74] -
DC.B 0 ; [$75] -
DC.B 0 ; [$76] -
DC.B 0 ; [$77] -
DC.B -1 ; [$78] Read Interrupt Flag Register.
DC.B -1 ; [$79] Read Modem Interrupt Data
DC.B -1 ; [$7A] -
DC.B -1 ; [$7B] -
DC.B -1 ; [$7C] -
DC.B -1 ; [$7D] -
DC.B 0+1 ; [$7E] Enter Shutdown Mode
DC.B 0+1 ; [$7F] Enter Sleep Mode
DC.B 0 ; [$80] Set Wakeup Timer
DC.B 0 ; [$81] -
DC.B 0 ; [$82] Disable Wakeup Timer
DC.B 0 ; [$83] -
DC.B 0 ; [$84] -
DC.B 0 ; [$85] -
DC.B 0 ; [$86] -
DC.B 0 ; [$87] -
DC.B 5+1 ; [$88] Read Wakeup Timer
DC.B -1 ; [$89] -
DC.B -1 ; [$8A] -
DC.B -1 ; [$8B] -
DC.B -1 ; [$8C] -
DC.B -1 ; [$8D] -
DC.B -1 ; [$8E] -
DC.B -1 ; [$8F] -
DC.B 0 ; [$90] Set Sound Control Bits
DC.B 0 ; [$91] Set DFAC Control Register
DC.B 0 ; [$92] -
DC.B 0 ; [$93] -
DC.B 0 ; [$94] -
DC.B 0 ; [$95] -
DC.B 0 ; [$96] -
DC.B 0 ; [$97] -
DC.B 1+1 ; [$98] Read Sound Control Status
DC.B 1+1 ; [$99] Read DFAC Control Register
DC.B -1 ; [$9A] -
DC.B -1 ; [$9B] -
DC.B -1 ; [$9C] -
DC.B -1 ; [$9D] -
DC.B -1 ; [$9E] -
DC.B -1 ; [$9F] -
DC.B 0 ; [$A0] Write Modem Register
DC.B 0 ; [$A1] Clear Modem Register Bits
DC.B 0 ; [$A2] Set Modem Register Bits
DC.B 0 ; [$A3] Write DSP RAM
DC.B 0 ; [$A4] Set Filter Coefficients
DC.B 0 ; [$A5] Reset Modem
DC.B 0 ; [$A6] -
DC.B 0 ; [$A7] -
DC.B 1+1 ; [$A8] Read Modem Register
DC.B 0 ; [$A9] Send Break
DC.B 0 ; [$AA] Dial Digit
DC.B 0 ; [$AB] Read DSP RAM
DC.B -1 ; [$AC] -
DC.B -1 ; [$AD] -
DC.B -1 ; [$AE] -
DC.B -1 ; [$AF] -
DC.B 0 ; [$B0] -
DC.B 0 ; [$B1] -
DC.B 0 ; [$B2] -
DC.B 0 ; [$B3] -
DC.B 0 ; [$B4] -
DC.B 0 ; [$B5] -
DC.B 0 ; [$B6] -
DC.B 0 ; [$B7] -
DC.B -1 ; [$B8] -
DC.B -1 ; [$B9] -
DC.B -1 ; [$BA] -
DC.B -1 ; [$BB] -
DC.B -1 ; [$BC] -
DC.B -1 ; [$BD] -
DC.B -1 ; [$BE] -
DC.B -1 ; [$BF] -
DC.B 0 ; [$C0] -
DC.B 0 ; [$C1] -
DC.B 0 ; [$C2] -
DC.B 0 ; [$C3] -
DC.B 0 ; [$C4] -
DC.B 0 ; [$C5] -
DC.B 0 ; [$C6] -
DC.B 0 ; [$C7] -
DC.B -1 ; [$C8] -
DC.B -1 ; [$C9] -
DC.B -1 ; [$CA] -
DC.B -1 ; [$CB] -
DC.B -1 ; [$CC] -
DC.B -1 ; [$CD] -
DC.B -1 ; [$CE] -
DC.B -1 ; [$CF] -
DC.B 0 ; [$D0] Reset CPU
DC.B 0 ; [$D1] -
DC.B 0 ; [$D2] -
DC.B 0 ; [$D3] -
DC.B 0 ; [$D4] -
DC.B 0 ; [$D5] -
DC.B 0 ; [$D6] -
DC.B 0 ; [$D7] -
DC.B 1+1 ; [$D8] Read A/D Status
DC.B 1+1 ; [$D9] Read User Input
DC.B -1 ; [$DA] -
DC.B -1 ; [$DB] -
DC.B 1+1 ; [$DC] read external switches
DC.B -1 ; [$DD] -
DC.B -1 ; [$DE] -
DC.B -1 ; [$DF] -
DC.B 0 ; [$E0] Write to internal PMGR memory
DC.B 0 ; [$E1] Download Flash EEPROM Code
DC.B 0+1 ; [$E2] Get Flash EEPROM Status
DC.B 0 ; [$E3] -
DC.B 0 ; [$E4] -
DC.B 0 ; [$E5] -
DC.B 0 ; [$E6] -
DC.B 0 ; [$E7] -
DC.B -1 ; [$E8] Read PMGR internal memory
DC.B -1 ; [$E9] -
DC.B 1+1 ; [$EA] Read PMGR firmware version number
DC.B -1 ; [$EB] -
DC.B -1 ; [$EC] Execute self test
DC.B -1 ; [$ED] PMGR diagnostics (selector-based)
DC.B -1 ; [$EE] -
DC.B 0 ; [$EF] PMGR soft reset
DC.B 0 ; [$F0] -
DC.B 0 ; [$F1] -
DC.B 0 ; [$F2] -
DC.B 0 ; [$F3] -
DC.B 0 ; [$F4] -
DC.B 0 ; [$F5] -
DC.B 0 ; [$F6] -
DC.B 0 ; [$F7] -
DC.B -1 ; [$F8] -
DC.B -1 ; [$F9] -
DC.B -1 ; [$FA] -
DC.B -1 ; [$FB] -
DC.B -1 ; [$FC] -
DC.B -1 ; [$FD] -
DC.B -1 ; [$FE] -
DC.B -1 ; [$FF] -
;________________________________________________________________________________________ <K11>
;
; _CommsPower - Communications' port power control
; _SerialPower ($A685) - Serial port power control
;
; Enter with: D0 = bit pattern
; BIT INDICATION
; 0 1 = ignore internal modem
; 1 not used
; 2-6 0000 = Do something to port B serial
; 0001 = Do something to port A serial/modem
; 0010 = Do something to port C modem
; 0011 = Do something to Ethernet Port
; 0100 thru 1111 are not used (yet)
; 7 1 = power port OFF
; 0 = power port ON
; Enter with: D1 - trap word
;
; Implementation:
; The SerialPower (now also CommsPower) code now resides in the CommsPowerTables of the
; Power Manager Primitives.
;
; History:
; The TIM internal (serial) modem is multiplexed thru port A. So bit 0 controls
; the use of the internal modem. When port C was created (for Dart), the used of it
; was backpatched to TIM. Now if you power ON port A and a serial modem is installed,
; as in TIM, the 'power A ON' code calls 'power C ON', which turns the modem on.
;
; On Dart, the internal modem is not multiplexed thru serial port A. To Power on the
; modem, call 'power C ON' directly.
;
; On Blackbird, the internal modem is not multiplexed thru serial port A. To Power on the
; modem, call 'power C ON' directly. Onboard Ethernet is treated like another port; Call
; 'Power Enet ON' directly.
;
; To power the SONIC LP:
; Turn on power to the SONIC (assert Whitney signal ENET_RESET_L)
; Wait for crystal to stabilize (50 ms, a LONG time)
; Deassert SLEEP line (deassert Whitney signal ENET_RESET_L)
;
; -------------------
; For Posterity, the TIM Algorithm:
; Determine what needs to be powered on for the SCC port that is being opened. There
; are two SCC ports (A/B) which may be connected to the external ports (the modem and
; printer ports), or the internal modem (for port B only).
;
; 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:
; make MODEM_RESET an input (to assert reset) - signal will float up
; turn on +5V and -5V to modem (MODEM_PWROUT)
; wait >2ms to allow +5V and -5V to settle
; enable the modem (*MODEM_PWR)
; turn on SCC
; wait >5ms to allow reset time
; make MODEM_RESET an output
; write a zero to MODEM_RESET to de-assert reset - drive it low
;
;________________________________________________________________________________________
CommsPower
SerialPower
with PrimInfoTbleRec,PmgrRec,PmgrPramRec,PmgrPrimitivesRec,ModemTblRec,CommsPwrTblRec
@workregs REG d1-d2/a0 ; <K19>
movem.l @workregs,-(sp) ; save our regs <K19>
move.l PMgrBase, a0 ; point to Power Manager globals <K14>
LoadTbl PmgrCommTblPtr,a0,a0 ; get pointer to Comms Power primitive table <K14>
beq @OutOfRange ; sorry no table
clr.l d1 ; clear work register
move.w d0,d1 ; get a copy of d0 to work on
asr.w #2,d1 ; right justify selector field
andi.w #$1f,d1 ; mask only selector field
move.l CommsPwrCount(a0), d2 ; length of table
asr.l #2, d2 ; number of entries in table
asr.l #1, d2 ; half as many valid selectors as entries
cmp.l d2, d1 ; are we in range?
bhs.s @OutOfRange ; no, so punt
btst #7,d0 ; is it on or off
beq.s @on ; on, so look at first half of table
add.l d2, d1 ; off, so look at second half of table
@on
tst.l ([a0, d1.l*4]) ; is there a routine?
beq.s @done ; zero offset means no rtn
jsr ([a0, d1.l*4]) ; go execute routine <K19>
moveq #noErr, d0 ; everything just dandy <K19>
bra.s @done ; <K19>
@OutOfRange
MOVE.W #paramErr,D0 ; Abort and return error
@done movem.l (sp)+,@workregs ; restore our regs <K19>
RTS
;——————————————————————————————————————————————————————————————————————————————————————— <t28> djw
; Modem Sound Interrupt Handlers
;
; Modem sound on Tim is implemented through DFAC's aux channel. The modem demands
; and releases the sound path through the MODEM_SND_ENABLE signal (on VIA1 CB2). The
; system monitors that bit to determine whether it should enable or disable the modem
; sound path.
;
; When the modem is powered, a CB2 interrupt handler is installed. When the modem
; demands sound, we immediately enable the sound path. The interrupt handler then
; re-configures the VIA CB2 interrupt to trigger on the falling edge. A new interrupt
; handler is installed which disables the sound path. The interrupt handlers ping-pongs
; back a
;
; Input: none
; Output: none
;
ModemSndOnInt
move.b #(1<<ifCB2),([VIA],vIFR) ; clear interrupt flag reg
move.b SDVolume,d0 ; get current volume <H37>
jsrTBL sndPlayThruVol ; set volume for playthrough <H37>
moveq.l #sndAuxiliary,d0 ; <H37>
jsrTbl sndInputSelect ; select aux source <H37>
bclr.b #6,([VIA],vPCR) ; change from pos to neg edge int
lea ModemSndOffInt,a0 ; disable sound routine
move.l a0,jModemSnd ; install in Level 1 VIA1 dispatch table
rts
;——————————————————————————————————————————————————————————————————————————————————————— <H59>
; Modem Sound Interrupt Handlers |
; V
; Modem sound on Tim is implemented through DFAC's aux channel. The modem demands
; and releases the sound path through the MODEM_SND_ENABLE signal (on VIA1 CB2). The
; system monitors that bit to determine whether it should enable or disable the modem
; sound path.
;
; When the modem is powered, a CB2 interrupt handler is installed. When the modem
; demands sound, we immediately enable the sound path. The interrupt handler then
; re-configures the VIA CB2 interrupt to trigger on the falling edge. A new interrupt
; handler is installed which disables the sound path. The interrupt handlers ping-pongs
; back a
;
; Input: none
; Output: none
;
ModemSndOffInt
move.b #(1<<ifCB2),([VIA],vIFR) ; clear interrupt flag reg
moveq.l #0,d0 ; disable playthrough
jsrTBL sndPlayThruVol ;
moveq.l #sndInputOff,d0
jsrTbl sndInputSelect ; disable aux source
bset.b #6,([VIA],vPCR) ; change from neg to pos edge int
lea ModemSndOnInt,a0 ; enable sound routine
move.l a0,jModemSnd ; install in Level 1 VIA1 dis≈ table
rts
;________________________________________________________________________________________
;
; IdleState ($A485) - Increments/decrements the idle enable flag count and returns
; the current speed.
;
; Enter with: D0 < 0, read speed
; Exit with: D0 = current speed
;
; Enter with: D0 = 0, enable idle
; Exit with: D0 = idle disable count
;
; Enter with: D0 > 0, disable idle
; Exit with: D0 = idle disable count
;________________________________________________________________________________________
IdleState
TST.L D0 ; What selector do we have
BGT IdleDisable ; D0 > 0
BEQ IdleEnable ; D0 = 0
BMI IdleRead ; D0 < 0
;________________________________________________________________________________________
;
; GoToSleep, WakeUp, SleepQInstall, SleepQRemove
;
; Enter : D1 = trap word
; D0 = Sleep type
;
; Exit : All regs unchanged
;
; SlpQInstall adds a sleep queue entry into the sleep queue.
;
; SlpQRemove deletes a sleep queue entry from the sleep queue.
;
; GoToSleep is called by the event manager when it determines that
; there is no work being done. Drivers are called to save their state,
; then the PMGR is ordered to put the system to sleep. When a waking
; event occurs, the PMGR powers up the system. The reset code jumps to
; WakeUp if the sleep flag is set. WakeUp restores the system hardware
; state, reloads the 68000 regs, and returns to the calling routine.
;________________________________________________________________________________________
GoToSleep BTST #9,D1 ; $A28A
BNE SlpQInstall
BTST #10,D1 ; $A48A
BNE SlpQRemove
*** BRA @Sleep ; $A08A
@Sleep
MOVE.L PMgrBase,A0 ; Get Power Manager Base Pointer
BSET #InSleep,PmgrFlags(A0) ; test and set sleep semaphore
BNE.S @Exit ; if in sleep, exit! don't re-enter
MOVE.L D0,D1 ; Save the sleep type
BSR.W SetSupervisorMode ; Set the machine to supervisor mode
MOVE.W D0,SaveCPUState.\
CPUSRsave(A0) ; Save the store away the status register
MOVE.W D0,PwrCycSave.\
PCRSRsave(A0) ; Save this stupid value for historical purposes
MOVE.L D1,D0 ; restore the sleep type
BSR.S TakeASnooze ; Take a snooze
MOVE.W SaveCPUState.\
CPUSRsave(A0),SR ; Restore the Status Register to the proper world
@Exit
RTS
;________________________________________________________________________________________
;________________________________________________________________________________________
TakeASnooze
SleepRegs REG A0-A6/D1-D7
MOVEM.L SleepRegs,-(SP) ; Save registers
MOVE.L D0,D2 ; Save a sleep type in D2
@checkinprogress
BTST #dockNoSleep,\
dockFlags(A0) ; is sleeping allowed (if we're connected to a bar)
BEQ.S @checkAuto ; -> yes, onward!
BSR.L DockingSleepDenied ; have the Docking Manager put up a notification
BRA AbortSleep ; then abort!
@checkAuto CMP.B #SleepRequest,D0 ; auto sleep request
BEQ.S @validselector
@checkDnd CMP.B #SleepDemand,D0 ; User sleep, from finder or command key
BEQ.S @validselector
@checkNow CMP.B #SleepNow,D0 ; Critical low power sleep
BNE AbortSleep
@validselector
MOVE.W SaveCPUState.\
CPUSRsave(A0),SR ; Restore the SR so that when VM is on the queue is run in User Mode
BCLR #AvoidNetDiag,\
PmgrFlags(A0) ; tst/clear the avoid bit
BNE.S @traverse ; if bit was set, skip dialog
MOVE.L SleepNetHook(A0),D1 ; IF SleepNetHook present THEN
BEQ.S @nextHook ;
MOVEA.L D1,A1 ; Get pointer
JSR (A1) ; Call Hook
BNE AbortSleep ; IF Bad Close THEN exit
@nextHook ; ELSE
MOVE.L SleepHook(A0),D1 ; IF SleepNetHook present THEN
BEQ.S @closeAT ;
MOVEA.L D1,A1 ; Get pointer
JSR (A1) ; Call Hook
@closeAT ; ENDIF
BSR.W CheckAppleTalk ; Close AppleTalk
BNE AbortSleep ; Branch if close denied
@traverse MOVE.W D2,D0 ; Restore D0
CMP.W #SleepNow,D0 ; If passing sleepnow to sleepq then change it
BNE.S @doQ ; to a sleep demand
MOVEQ #SleepDemand,D0 ; sleepNow -> sleepDemand
@doQ BSR.W DoQueueStack ; Walk the queue
MOVE.L D0,D1 ; Save a copy of DoQueueStack result
BSR.W SetSupervisorMode ; Return to supervisor mode so that we may continue
TST.L D1 ; DoQueueStack == Ok to goto sleep ?
BNE.W AbortSleep ; Nope. Get out!
BSR.W CloseAppleTalk ; Else shut down atalk
BCLR #InSleep,PmgrFlags(A0) ; clr the sleep indicator
BCLR #PmgrShutdownEnb,\
PmgrFlags1(A0) ; disable shutdown across sleep
MOVEA.L A0,A2 ; A2 = Power Manager Vars
BSR.W SaveSetCrsr ; Save and Set cursor to a watch cursor
; run thru the table of machine-specific operations to perform for going to sleep...
ORI.W #HiIntMask,SR ; Disable interrupts
BackToSleep
LoadTbl SleepTblPtr,A2,A0 ; get pointer to the SleepTable
LEA @Resume,A1 ; set up return address in A1
BRA.S @Resume ; WHILE tableItem != NIL DO {
@SaveLoop MOVEA.L D0,A2 ; get address of calling routine
JMP (A2) ; do the routine
@Resume MOVE.L (A0)+,D0 ; increment to the next table item
BNE.S @SaveLoop ; }
BRA.S * ; wait for sleep (yawn...)
AbortSleep BSR.W SetSupervisorMode ; Set the machine to supervisor mode
BCLR #InSleep,PmgrFlags(A0) ; Clear the sleep indicator
MOVE.W D2,D0 ; Restore sleep type to D0
MOVEM.L (SP)+,SleepRegs
RTS ; Return to caller
;________________________________________________________________________________________
; WakeUp is reached from the reset (power up) code if the sleep flag is set.
;
; Enter : A2 = Pointer to Pmgr Globals
; Exit : All regs unchanged
;________________________________________________________________________________________
WakeUp
ORI.W #HiIntMask,SR ; no more interrupts
MOVEA.L PmgrBase,A0 ; make sure that we have pointer to PmgrBase
LoadTbl WakeTblPtr,A0,A0 ; get pointer to the WakeTable
LEA @Resume,A1 ; set up return address in A1
BRA.S @Resume ; WHILE tableItem != NIL DO {
@RestoreLp MOVEA.L D0,A2 ; get address of calling routine
JMP (A2) ; do the routine
@Resume MOVE.L (A0)+,D0 ; increment to the next table item
BNE.S @RestoreLp ; }
MOVEA.L PmgrBase,A2 ; point to the Power Manager globals <H47>
BTST #dockNoWakeup,\ ; <H47>
dockFlags(A2) ; can we wakeup with this bar attached? <H47>
BEQ.S @CanWakeup ; -> yes, continue waking up <H47>
MOVEM.L (SP),SleepRegs ; restore the registers but don't touch the stack <H47>
MOVEA.L PmgrBase,A2 ; point to the Power Manager globals again <H47>
BSR.L DockingWakeupDenied ; setup the notification message <H47>
BRA BackToSleep ; then go put the machine back to sleep <H47>
@CanWakeup ; <H47>
MOVEM.L (SP),SleepRegs ; Restore the registers but don't touch the stack
BSR.L SCSIDiskWakeAlert ; check if a disk mode cable is plugged in <H64>
BSR.L InitSCSIHW ; Init the SCSI chip
LEA Time,A0 ; load parameter for ReadDateTime
_ReadDateTime
BSR KbdReset ; clear the keyboard maps
MOVEA.L PmgrBase,A2 ; Get Power Manager globals base
TST.L WakeUpHook(A2) ; Do we have a sleep hook?
BEQ.S @noHook ; Nope... go on
MOVE.L WakeUpHook(A2),A0 ; Get the sleep hook
JSR (A0) ; Go do it...
@noHook
MOVE.W SaveCPUState.\
CPUSRsave(A2),SR ; Restore the SR so that when VM is on the queue is run in User Mode
_ADBReInit ; Init the ADB devices <H56>
_ShowCursor ; Alive now tell the user it's OK <H56>
BSR.W MPPOpen ; Open the driver since elements in the queue might need some MPP services
MOVEQ #SleepWakeUp,D0 ; Go through wake queue
BSR.W DoQueue ; Run through the queue in proper order
MOVEA.L PmgrBase,A2 ; Get Power Manager globals base
BSR.W RemoveMsg
CLR.B Level4Cnt(A2) ; Clear level 4 count down timer
MOVE.B #-1,LastLevel(A2) ; Reset battery level <v2.8>
CLR.L BatQ(A2) ; Clear queue
CLR.L BatQ+4(A2)
MOVE.B #8,BatQIndex(A2) ; Reset index
BCLR #PmgrShutdownReq,\
PmgrFlags1(A2) ; clear any shutdown request <H37>
BSET #PmgrShutdownEnb,\
PmgrFlags1(A2) ; enable shutdown <H37>
BSR.W RestoreScreen ; Restore cursor and screen and back into the world.
BSR.W SetSupervisorMode ; Return to supervisor mode <H66>
MOVEM.L (SP)+,SleepRegs ; Now really restore the world
MOVEQ #0,D0 ; and return a zero result <H69>
RTS
;________________________________________________________________________________________
;
; CheckAppleTalk - checks AppleTalk drivers depending on the sleep
; level, what is open, and what the user OK's.
;
;________________________________________________________________________________________
STRING PASCAL
CheckAppleTalk
MOVEM.L A0-A3/D1-D2,-(SP) ; Try to close AppleTalk and warn user of this <v1.4>
SUB.W #ioQElSize,SP ; Allocate IO stack frame
MOVE.L SP,A3 ; Save this place
MOVE.L PmgrBase,A2 ;
MOVEQ #$0F,D1 ; Lower nibble indicates ATalk in use
AND.B PortBUse,D1
CMP.B #1,D1
BNE @okexit ; Do exit if no Atalk
MOVE.W D0,D1 ; Case on request, demand, and now sleeps
CMP.B #SleepRequest,D0 ; Request case
BNE.S @dmndcase
;________________________________________________________________________________________
; Request sleep (time out) case. If plugged in or chooser bit set or server mounted then sleep
; denied, else ok.
;________________________________________________________________________________________
@reqcase BTST #noATChg,ChooserBits ; If magic chooser bit set then no sleep
BEQ @done
BTST #HasCharger,Charger(A2) ; If plugged in then no sleep
BNE @done
BTST #XPPLoadedBit,PortBUse ; Test for XPP in use
BNE.S @reqcase1 ; Branch if so
MOVE.B #ClosedMPP,WakeWarn(A2) ; Set flag for wake up warning (MPP closed)
BRA @okexit ; Bye now
@reqcase1 BSR XPPCheck ; Try to close XPP
BNE @done ; Branch if not
MOVE.B #ClosedXPP,WakeWarn(A2) ; Set flag for wake up warning (XPP closed)
BRA @okexit
;________________________________________________________________________________________
; Demand sleep (Finder - Battery DA) case. User warned of different conditions and given the choice
; to sleep or not.
;________________________________________________________________________________________
@dmndcase CMP.B #SleepDemand,D0 ; Demand case
BNE.S @nowcase
BTST #noATChg,ChooserBits ; If no magic chooser bit then branch
BNE.S @dmndcase1
; Magic chooser bit is set so give the user the big bad warning.
BSR.W HarshWarn ; Warn user of impending doom
BNE @done ; No sleep if user is scared off
MOVE.B #ClearedChsr,WakeWarn(A2) ; Set flag for wake up warning (magic bit cleared)
BSET #noATChg,ChooserBits ; Clear magic chooser bit
BRA @okexit
; Only MPP is open so give the user the wimpy warning.
@dmndcase1 BTST #XPPLoadedBit,PortBUse ; Test for XPP in use
BNZ.S @dmndcase2 ; Branch if so
BSR.W WimpyWarn ; Warn user of possible problems
BNE.S @done ; Branch if chickened out
MOVE.B #ClosedMPP,WakeWarn(A2) ; Set flag for wake up warning (MPP closed)
BRA.S @okexit ; We're cool
; XPP is open and a server may be mounted. If no server then give the wimpy warning, else
; give a stronger one.
@dmndcase2 BSR XPPCheck ; Try to close XPP
BNE.S @dmndcase3 ; Branch if not able
BSR.W WimpyWarn ; Warn user of possible problems
BNE.S @done ; Branch if chickened out
MOVE.B #ClosedXPP,WakeWarn(A2) ; Set flag for wake up warning (XPP closed)
BRA.S @okexit ; We're cool
; Server is mounted so give the strong warning.
@dmndcase3 BSR.W StrongWarn ; Be firm but gentle
BNE.S @done ; Talked him out of it
MOVE.B #ClosedSvr,WakeWarn(A2) ; Set flag for wake up warning (server lost)
BRA.S @okexit ; It was rough but we're fine
;________________________________________________________________________________________
; Now sleep (Low power) case. Close any and all but select the right wake up warning.
;________________________________________________________________________________________
@nowcase MOVE.B #ClearedChsr,WakeWarn(A2) ; Set flag for wake up warning (magic bit cleared)
BSET #noATChg,ChooserBits ; Clear magic chooser bit
BEQ.S @nowcase4 ; Branch if bit was active
MOVE.B #ClosedMPP,WakeWarn(A2) ; Set flag for wake up warning (MPP closed)
BTST #XPPLoadedBit,PortBUse ; Test for XPP in use
BNZ.S @nowcase4 ; Branch if so
MOVE.B #ClosedXPP,WakeWarn(A2) ; Set flag for wake up warning (XPP closed)
BSR XPPCheck ; Try to close XPP
BEQ.S @nowcase4 ; Branch if did
MOVE.B #ClosedSvr,WakeWarn(A2) ; Set flag for wake up warning (server lost)
@nowcase4
@okexit MOVEQ #0,D0
@done ADD.W #ioQElSize,SP ; Release stack frame
MOVEM.L (SP)+,A0-A3/D1-D2
TST.W D0
RTS
;________________________________________________________________________________________
;
; 91/02/13 - AG
;
; Close appletalk drivers if necessary
;
;________________________________________________________________________________________
CloseAppleTalk
MOVEM.L A0-A3/D1-D2,-(SP) ; Try to close AppleTalk and warn user of this <v1.4>
SUB.W #ioQElSize,SP ; Allocate IO stack frame
MOVE.L SP,A3 ; Save this place
MOVE.L PmgrBase,A2 ;
MOVEQ #$0F,D1 ; Lower nibble indicates ATalk in use
AND.B PortBUse,D1
CMP.B #1,D1
BNE @Closedone ; Do exit if no Atalk
BSR.W AllClose ; Shutdown everything
@Closedone ADD.W #ioQElSize,SP ; Release stack frame
MOVEM.L (SP)+,A0-A3/D1-D2
TST.W D0
RTS
;———————————————————————————————————————————————————————————————————————
; CloseATalk support routines.
;———————————————————————————————————————————————————————————————————————
StrongWarn MOVE.W #-16386,D0
BRA.S Warn
WimpyWarn MOVE.W #-16387,D0
BRA.S Warn
HarshWarn MOVE.W #-16388,D0
Warn CLR.W -(SP) ; Send the warning
MOVE.W D0,-(SP)
CLR.L -(SP)
_Alert
MOVE.W (SP)+,D0 ; D0 non-zero if canceled
SUBQ.W #1,D0 ; <t31> 1 is sleep button
RTS
MPPClose MOVE.L A3,A0 ; Get stack frame pointer
MOVE #~MPPUnitNum,ioRefNum(A0) ; Close MPP
_Close
TST.W D0
RTS ; Sucess returned in status
XPPClose MOVE.L A3,A0 ; Get stack frame pointer
LEA #'.XPP',A1 ; Get XPP refnum
MOVE.L A1,ioVNPtr(A0)
MOVE.B #fsCurPerm,ioPermssn(A0)
_Open
_Close ; Close XPP
TST.W D0
RTS ; Sucess returned in status
AllClose MOVE.L A3,A0 ; Get stack frame pointer
LEA #'.XPP',A1 ; Get XPP refnum
MOVE.L A1,ioVNPtr(A0)
MOVE.B #fsCurPerm,ioPermssn(A0)
_Open
MOVE #CloseAll,csCode(A0) ; Close everything
_Control
_Close
MOVE #~MPPUnitNum,ioRefNum(A0); Close MPP
_Close
TST.W D0
RTS ; Sucess returned in status
;———————————————————————————————————————————————————————————————————————
;
; MPPOpen - routine to open the MPP driver. If the driver is not necessary, the open
; will fail, so just try to open the driver blindly
;
; input
; none
;
; output
; none
;
; usage
; a0 - pointer to iopb
; a1 - pointer to driver name
;
;———————————————————————————————————————————————————————————————————————
MPPOpen MOVEM.L A0-A3/D1-D2,-(SP)
;•••••••••••••••• <K14>
; temporarily don't even call this!
; so we stop switching from ethertalk to localtalk across sleep
IF BlackBirdDebug THEN
TestFor PrattExists
bne.s @skipit
BSR SelectAtlkPort ; make sure AppleTalk knows which port to use <H67>
@skipit
ENDIF
;•••••••••••••••• <K14>
LEA -ioQElSize(SP),SP ; Allocate IO stack frame
MOVEA.L SP,A0 ; Save this place
LEA #'.MPP',A1 ; Get MPP refnum
MOVE.L A1,ioVNPtr(A0)
MOVE.B #fsCurPerm,ioPermssn(A0)
_Open
LEA ioQElSize(SP),SP ; Release stack frame
MOVEM.L (SP)+,A0-A3/D1-D2
RTS
;________________________________________________________________________________________
;
; Routine: SelectAtlkPort
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0-D1/A0-A1
;
; Function: Calls the lmgr to see if the AppleTalk connection in use
; before going to sleep is still available. If it isn't, it
; switches to the preferred connection (usually SCC port B).
;________________________________________________________________________________________
SelectAtlkPort ; <H67>
MOVE.W #mapTrue,RomMapInsert ; map the ROM into the resource chain
SUBQ.W #4,SP
PEA 'lmgr' ; theType
CLR.W -(SP) ; theID
_GetResource ; try to load the lmgr
MOVE.L (SP)+,D0 ; did we get it
BEQ.S @NoLmgr ; -> no, just exit
MOVEA.L D0,A0 ; get the handle to the lmgr
MOVE.L A0,-(SP) ; and push a copy for ReleaseResource
CLR.L -(SP) ; param1 (none)
CLR.L -(SP) ; param2 (none)
PEA 6 ; selector
MOVEA.L (A0),A0
JSR 2(A0) ; call the lmgr to switch the atlk if necessary
LEA 12(SP),SP ; (toss parameters, C style)
_ReleaseResource ; all done, so unload the resource
@NoLmgr RTS
;________________________________________________________________________________________
;
; 91/02/13 - AG
;
; DoQueueStack - this routine is called to traverse the sleep queue. if
; the sleep type is "now", "demand", or "WakeUp", the queue will only
; be run once. otherwise, the queue will be run twice. once to check if
; its ok to sleep, if ok, the sleep type is changed to "demand" and the
; queue is rerun. if not ok, then the sleep type is change to "Unlock"
; and the queue is rerun, Each proc is passed its queue entry in A0.
;
; input
; d0 sleep type
; a0 ptr to pmgrglobals
;
; output
; d0
; == 0 ok to sleep
; != 0 queue rejected auto sleep
;
; usage
; d d0 sleep type/result
; a0 pointer to first element/ ptr to pmgrglobals
;
;———————————————————————————————————————————————————————————————————————
DoQueueStack
MOVEM.L A0/D1,-(SP) ; save pmgrglobals ptr
MOVE.L SlpQHead(A0),A0 ; Get ptr to first element
CMP.W #SleepRequest,D0 ; is it auto sleep ?
BNE.S @runTheQueue ; if no, just run the queue
@testTheQueue
BSR.s Handle_Element ; ask queue about auto sleep
BNE.s @undosleepreq ; if error returned, undo sleep
MOVEQ #SleepDemand,D0 ; ... else set to sleep demand
@runTheQueue
BSR.S Handle_Element ; handle element
CLR.L D0 ; return no error
@exit MOVEM.L (SP)+,A0/D1 ; restore pmgrglobals ptr
RTS
@undosleepreq
MOVEQ #SleepUnlock,D0 ; Since sleep denied, set to unsleep
BSR.S Handle_Element ; handle element
MOVEQ #SleepUnlock,D0 ; return non zero result
BRA.S @exit
;———————————————————————————————————————————————————————————————————————
;
; Handle Element - this is a routine which is used to execute a queue element. if the
; element pointer is null, the routine exits and returns 0 in d0. if the element
; pointer is not null, then the routine will do two thing:
; 1) handle the next element recursively
; 2) execute the current element's sleep proc
; the queue will essentially be traversed in post fixed order
;
; input
; a0 pointer to queue element
; d0 sleep type
;
; output
; d0 result
; == 0 ok to sleep
; != 0 sleep rejected
;
; Usage
; a0 pointer to element
; d a1 pointer to sleep proc
; d d0 sleep type/result
; d d1 saved sleep type/ condition code check
;
;———————————————————————————————————————————————————————————————————————
ProcRegs REG a0-a6/d1-d7
Handle_Element
MOVE.L a0,d1 ; test element pointer
BEQ.S @noelement ; if invalid element ptr, exit with d0 clear
MOVE.L d0,d1 ; save a copy of type in d1
@validelement
MOVEM.L a0/d1,-(sp) ; save element pointer and type
MOVE.L SleepqLink(a0),a0 ; pass in pointer to next element
BSR.S Handle_Element ; handle the next element in queue
MOVEM.L (sp)+,a0/d1 ; restore pointer and type
BNE.S @exit ; if result != zero, exit
@callproc
MOVE.L SleepqProc(a0),D0 ; get a pointer to the proc <H33>
BEQ.S @noelement ; if no pointer, exit; flags set by move <H33>
MOVEA.L d0,a1 ; load pointer in address register for execution <H33>
MOVE.L d1,d0 ; restore type to d0
MOVEM.L ProcRegs,-(sp) ; save the world before calling proc <15> ag
JSR (a1) ; call sleep proc
MOVEM.L (sp)+,ProcRegs ; restore the world
CMP.W #SleepRequest,D1 ; is this request or demand? <H13>
BNE.S @noelement ; IF NOT Request THEN clear result & exit <H13>
TST.L d0 ; ELSE set condition codes on result <H13>
RTS ; <H13>
@noelement moveq #0,d0 ; clear result
@exit RTS ; exit
;———————————————————————————————————————————————————————————————————————
;
; XPPCheck - this is a routine checks to see if any servers are mounted.
; D0 will return the error from the close. if no error, no servers!
; to restore the world, reopen the driver after.
;
; input
; a3 pointer to pb
;
; output
; d0 result
; == 0 no servers mounted
; != 0 servers mounted
;
; Usage
; a0 pointer to pb
; a1 pointer to driver name
; a3 pointer to pb
;
;———————————————————————————————————————————————————————————————————————
XPPCheck MOVE.L a3,a0 ; Get pb pointer
MOVE.W #~xppUnitNum,ioRefNum(A0) ;
_Close ; Close XPP
MOVE.L d0,-(sp) ; save result
LEA #'.XPP',a1 ; Get XPP refnum
MOVE.L a1,ioVNPtr(a0) ; load pointer to driver
MOVE.B #fsCurPerm,ioPermssn(a0) ; set permission
_Open ; get refnum
MOVE.L (sp)+,d0 ; restore result
TST.W d0 ; test close result
RTS ; Sucess returned in status
;———————————————————————————————————————————————————————————————————————
;
; DoQueue - Call each procedure in the sleep/wake queue with the parameter passed
; in D0. Each proc is passed its queue entry in A0.
;———————————————————————————————————————————————————————————————————————
DoQueue CMP.W #SleepNow,D0 ; Sleep now
BEQ.S @mustsleep
CMP.W #SleepDemand,D0 ; Sleep demand
BEQ.S @mustsleep
CMP.W #SleepWakeUp,D0 ; or wake calls are not denied
BEQ.S @mustsleep
@startreq MOVE.L D0,D7 ; Save call type
MOVE.L PmgrBase,A1
MOVE.L SlpQHead(A1),A0 ; Get head pointer to sleep queue entries
MOVE.L A0,D2
BEQ @noentries ; Skip rest if no entries
@getreq MOVE.L SleepqProc(A0),A2 ; Get sleep proc
MOVE.L A2,D2
BEQ.S @nextreq ; Go to next if no proc
MOVE.W D7,D0
MOVEM.L A0-A1,-(SP)
JSR (A2) ; Execute proc
MOVEM.L (SP)+,A0-A1
TST.L D0
BEQ.S @nextreq ; Request ok
CMP.W #SleepUnlock,D7 ; If unlocking then continue
BEQ.S @nextreq
MOVEQ #SleepUnlock,D0 ; Since sleep denied
MOVE.L D0,D7
BRA.S @startreq ; unlock everything
@nextreq CMP.L SlpQTail(A1),A0 ; Check for more entries
BEQ.S @checkreq ; Branch if no more
MOVE.L SleepqLink(A0),A0 ; Get next queue entry
BRA.S @getreq
@checkreq MOVEQ #SleepDemand,D0 ; Queue says sleep is ok
CMP.W #SleepUnlock,D7 ; If we were unlocking then we are done now
BNE.S @mustsleep
MOVEQ #SleepDeny,D0 ; Sleep request failed
RTS
; Sleep demand case
@mustsleep MOVE.W D0,D7 ; Save command
MOVE.L PmgrBase,A1
MOVE.L SlpQHead(A1),A0 ; Get head pointer to sleep queue entries
MOVE.L A0,D2
BEQ.S @noentries ; Skip rest if no entries
@getdemand MOVE.L SleepqProc(A0),A2 ; Get sleep proc
MOVE.L A2,D2
BEQ.S @nextdemand ; Go to next if no proc
MOVE.W D7,D0
MOVEM.L A0-A1,-(SP)
JSR (A2) ; Execute proc
MOVEM.L (SP)+,A0-A1
@nextdemand CMP.L SlpQTail(A1),A0 ; Check for more entries
BEQ.S @noentries ; Branch if no more
MOVE.L SleepqLink(A0),A0 ; Get next queue entry
BRA.S @getdemand
@noentries CLR.L D0
RTS
;———————————————————————————————————————————————————————————————————————
; KbdReset - Clears all keymaps
;———————————————————————————————————————————————————————————————————————
KbdReset BigJSR RSetKMap,A1 ; Reset global keymap <v2.9>
MOVEQ #numFDBAdr, D1 ; Number of table entries
MOVE.L ADBBase, A1 ; Put Base in A1
BRA.S @10 ; Skip past record increment
@loop ADD #FRecSize, A1 ; Get to next record
@10 MOVEQ #2, D0 ; We're looking for keyboards
CMP.B FDBOAddr(A1), D0 ; Is this one?
BNE.S @notkbd ; Nope, skip around
MOVE.L FDBOpData(A1),A0 ; Retrieve pointer to kbd data
LEA 4(A0),A0 ; Get address of keybits
MOVEQ #0,D0
MOVE.L D0,(A0)+ ; Clear the key bits
MOVE.L D0,(A0)+
MOVE.L D0,(A0)+
MOVE.L D0,(A0)+
@notkbd DBRA D1, @loop ; Loop until no more
RTS
STRING ASIS
;———————————————————————————————————————————————————————————————————————
;
; SlpQInstall/SlpQRemove - Installs/Removes entries in the sleep queue.
;
; Enrty: A0 = SlpQRec (pointer)
;
; Exit: D0 = Result code (word)
;———————————————————————————————————————————————————————————————————————
SlpQInstall
CMP.W #slpQType,SleepqType(A0)
BNE.S SlpQErr
MOVE.L PmgrBase,A1
LEA SleepQHdr(A1),A1
_Enqueue
RTS
SlpQErr MOVEQ #SlpTypeErr,D0
RTS
SlpQRemove CMP.W #slpQType,SleepqType(A0)
BNE.S SlpQErr
MOVE.L PmgrBase,A1
LEA SleepQHdr(A1),A1
_Dequeue
RTS
;•••••••••••••••••••••••••••••••• End of Traps ••••••••••••••••••••••••••••••••••••••••••
;••••••••••••••••••••••••••••••••••• Misc •••••••••••••••••••••••••••••••••••••••••••••••
;
; Contains:
;
; ResetPMGRInts
; SaveSetCrsr
; RestoreScreen
; SetSupervisorMode
; PMGRsend/recv
; SetPwrLvlTask
; DoSpinDown
; DoHDSpinUP
; PowerDownAll
; PortableCheck
;
;________________________________________________________________________________________
;________________________________________________________________________________________
;
; Routine: ResetPMGRInts
;
; Inputs: A1 - VIA1 base address
;
; Outputs: A1 - VIA1 base address
;
; Trashes: D0, D1, A0
;
; Function: clears any pending PMGR interupts and disables modem interrupts
;________________________________________________________________________________________
ResetPMGRInts ; clear any pending PMGR interrupts
MOVE.L VIA,A1 ; get VIA base address
MOVE.B #(1<<ifIRQ)+(1<<ifCB1),\
vIFR(A1) ; clear PMGR interrupts in the VIA
; read any pending PMGR interrupt data from PG&E so we don't hang in InitADB...
LEA -12(SP),SP ; allocate a buffer for interrupt data <H8>
MOVE.L SP,A0 ; and point to it <H8>
ADDQ.L #2,A0 ; (why do we have to do this?) <H8>
MOVEQ #ReadINT,D0 ; PMGR command = get interrupt data <H8>
BSR PMGRrecv ; go get the interrupt data (we'll just toss it) <H8>
; disable all modem interrupt sources so we won't get spurious level 3 interrupts from PG&E...
CLR.B (A0) ; data to send = disable all modem interrupt sources <H57>
MOVEQ #1,D1 ; 1 bytes to send <H57>
MOVEQ #SetModemInts,D0 ; command = set modem interrupt sources <H57>
BSR PMGRsend ; tell PG&E to turn them all off <H57>
LEA 12(SP),SP ; toss the buffer <H8>
MOVE.B #(1<<ifIRQ)+(1<<ifCB1),\
vIER(A1) ; enable PMGR interrupts in the VIA
RTS ; <H57>
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SaveSetCrsr
;
; Inputs: A2 - pointer to Power Manager variables
; A5 - Quickdraw globals
;
; Outputs: none
;
; Trashes: A0 - A1
;
; Function: Save current state of cursor and set cursor to a watch cursor.
;————————————————————————————————————————————————————————————————————————————————————————
SaveSetCrsr
MOVE.L (A5),A0 ; point to QuickDraw globals
LEA Arrow(A0),A0 ; Get pointer to current cursor
MOVE.L A0,SleepSaveCrsr(A2) ; save the address of cursor in our little storage
SUBA.L #4,SP ; Get some stack space <34> HJR
MOVE.W #watchCursor,-(SP) ; Get the watch cursor
_GetCursor
MOVE.L (SP)+,A0 ; Get handle to cursor
MOVE.L (A0),A0 ; Dereference once
MOVE.L A0,-(SP) ; push parameter on stack
_SetCursor
_HideCursor ; <H56>
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: RestoreScreen
;
; Inputs: A2 - pointer to Power Manager variables
; A5 - Quickdraw globals
;
; Outputs: none
;
; Trashes: A0
;
; Function: Restores the cursor to its previous state and updates the screen (but not
; in that order :-)
;————————————————————————————————————————————————————————————————————————————————————————
RestoreScreen
JsrRoutine ScreenRedrawPtr,A2,A0 ; (Calls RedrawScrn from the Primitives.)
MOVE.L SleepSaveCrsr(A2),-(SP) ; Get ptr to saved crsr
_SetCursor ; Set the cursor
_ShowCursor ; Show it to the world
RTS
;________________________________________________________________________________________
; SetSupervisorMode
;
; Input: None
;
; Destroys: D0/A1
;
; Called by: BSR from DreamAway & Wakeup.
;
; Function: When VM is running we must switch to supervisor mode so
; that we may run necessary priviledged instructions. Yes
; we are the operatorating system and that is acceptable!!!
;________________________________________________________________________________________
SetSupervisorMode
MOVE.L (SP)+,A1 ; Save a copy of return address since we might switch stacks
MOVEQ #8,D0 ; Set selector to Set Supervisor Mode for VM
_DebugUtil ;
CMPI.W #paramErr,D0 ; IF VM is on THEN D0 = Status Register
BNE.S @Cont ; ELSE
MOVE.W SR,D0 ; Save the current Status Register
@Cont ANDI.W #$EFFF,SR ; Make sure that we are in the interrupt stack
JMP (A1) ; Get out of here
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: PMGRsend/recv
;
; Inputs: A0 - data buffer
; D0 - command
; D1 - length
;
; Outputs: A0 - data buffer
; D0 - result code
;
; Trashes: A0 - A1
;
; Function: Handy PmgrOp calling routines.
;————————————————————————————————————————————————————————————————————————————————————————
PMGRrecv MOVEQ #0,D1 ; Get data from pmgr <v2.4>
PMGRsend MOVE.L A0,-(SP) ; pmRBuffer
MOVE.L A0,-(SP) ; pmSBuffer
MOVE.W D1,-(SP) ; pmLength
MOVE.W D0,-(SP) ; pmCommand
MOVE.L SP,A0
_PmgrOp
MOVE.W pmLength(sp),d1 ; return count <gmr>
LEA pmRBuffer(SP),SP ; Release stack frame
MOVE.L (SP)+,A0 ; pmRBuffer
RTS
;————————————————————————————————————————————————————————————————————————————————————————
; Routine: SetPwrLvlTask
;
; Inputs: A2 - PMgrBase
;
; Outputs: none
;
; Trashes: A0
;
; Function: set the power manager micro levels to match those set in the 680x0 pmgr globals
;————————————————————————————————————————————————————————————————————————————————————————
SetPwrLvlTask
@SetPwrLvlRegs REG A0-A1/D0-D1
MOVEM.L @SetPwrLvlRegs,-(SP) ; working registers
MOVE.W #$4201,-(SP) ; pushpram byte 0x42 + one byte of data
MOVE.W LowWarn(A2),-(SP) ; move the current 68K pmgr setting into buffer for set
MOVEA.L SP,A0 ; set up data buffer
MOVEQ #xPramWrite,D0 ; command to send
MOVEQ #3,D1 ; number of data bytes
BSR.S PMGRsend ; send command
CLR.L (SP)+ ; clean up buffer
MOVEM.L (SP)+,@SetPwrLvlRegs ; Restore working registers
RTS
;________________________________________________________________________________________ <H82>
;
; Routine: DoSpinDown
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0, A0
;
; Function: kills power to the internal hard disk, unless spindown is disabled
;________________________________________________________________________________________
DoSpinDown
MOVEM.L A0-A1,-(SP) ; save some registers
MOVEA.L PMgrBase,A1 ; point to the Power Manager's globals <H83>
BTST.B #QuickHDSpinDwn,PmgrFlags2(A1) ; quick spin down enabled? <H83>
BNE.S @MustSpindown ; -> yes, have to spin down even if disabled<H83>
IF HDSpinDownDisable=7 THEN
TST.B PmgrFlags2(A1) ; is spindown allowed? <H83>
BMI.S @Done ; -> no, ignore it <H83>
ELSE
BTST #HDSpinDownDisable,PmgrFlags2(A1) ; is spindown allowed? <H83>
BNE.S @Done ; -> no, ignore it <H83>
ENDIF
@MustSpindown ; <H83>
BCLR #HDPowerOn,PMgrFlags(A1); clear the flag, indicating that the drive is now spun down <K36>
; call each of the routines in the hard disk queue to notify anyone who cares
; that the hard disk is about to be spun down
MOVEM.L D1-D2/A1-A2,-(SP)
LEA hdQHead(A1),A2 ; point to the start of the hard disk queue
BRA.S @NoProc
@NextElement
MOVEA.L D0,A2 ; point to the next queue element
MOVE.L hdProc(A2),D0 ; get the pointer to the routine
BEQ.S @NoProc ; -> there isn't one
MOVE.L A2,-(SP) ; push a pointer to the queue element <H81>
MOVEA.L D0,A0 ; point to the routine
JSR (A0) ; and call it
@NoProc MOVE.L hdQLink(A2),D0 ; end of the queue?
BNE.S @NextElement ; -> no, keep running (huff! puff!)
MOVEM.L (SP)+,D1-D2/A1-A2
; finally, spin down the internal hard disk
MOVE.B #hdOff,-(SP) ; data to send = turn off hard disk power plane
MOVE.L SP,-(SP) ; pmRBuffer (not used)
MOVE.L (SP),-(SP) ; pmSBuffer
MOVE.W #1,-(SP) ; pmLength
MOVE.W #powerCntl,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; turn off the hard disk
LEA pmRBuffer+4+2(SP),SP ; clean up the stack
BNE.S @Done ; -> an error occurred
CLR.L LastHD(A1) ; stop calling - disk is spun down
BCLR #HDPowerOn,PMgrFlags(A1); clear the flag, indicating that the drive is now spun down
MOVEM.L (SP)+,A0-A1 ; restore some registers
@Done RTS
;________________________________________________________________________________________ <H82>
;
; Routine: DoHDSpinUp
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0, A0
;
; Function: restores power to the internal hard disk
;________________________________________________________________________________________
DoHDSpinUp
; This portion of code freezes the "Spin Down" timer for the hard disk, preventing
; the Power Mgr from cutting hard disk power during ANY SCSI transaction.
MOVEM.L A0-A1/D0,-(SP) ; save them regs
MOVEA.L PmgrBase,A1 ; point to Pmgr locals
MOVE.L #0,LastHd(A1) ; always freeze the spin down timer
BTST.B #HDPowerOn,PmgrFlags(A1) ; set flag indicating drive is now spun up <t11> djw
BNE.S @Done ; drive already spun up - skip PmgrOp call <t11> djw
MOVE.B #hdOn,-(SP) ; data to send = turn off hard disk power plane
MOVE.L SP,-(SP) ; pmRBuffer (not used)
MOVE.L (SP),-(SP) ; pmSBuffer
MOVE.W #1,-(SP) ; pmLength
MOVE.W #powerCntl,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; turn off the hard disk
LEA pmRBuffer+4+2(SP),SP ; clean up the stack
BNE.S @Done ; -> an error occurred
MOVE.L #250,D0 ; wait 250 Miliseconds
BigJsr DelayNMsec,A0 ; … Spin are wheels
BSET.B #HDPowerOn,PmgrFlags(A1) ; set flag indicating drive is now spun up <t11> djw
@Done MOVEM.L (SP)+,A0-A1/D0 ; restore them registers
RTS ; return to SCSIGet
;________________________________________________________________________________________
;
; Routine: PowerDownAll
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0, A0
;
; Function: called by StartInit to power down all peripheral subsystems
;________________________________________________________________________________________
PowerDownAll
TestFor hwCbPwrMgr ; is there Power Mgr in this Mac ?
BEQ.S @NoPMGR ; -> no, skip
MOVE.B #allOff,-(SP) ; buffer contains "turn off unused devices"
IF forRomulator THEN
ANDI.B #~((1<<pSCC)|(1<<pSerDrvr)|(1<<pMinus5V)),(SP) ; don't kill the nub! <SM69>
ENDIF
MOVE.L SP,-(SP) ; point to receive buffer
MOVE.L (SP),-(SP) ; point to transmit buffer
MOVE.W #1,-(SP) ; one byte of transmit data
MOVE.W #PowerCntl,-(SP) ; PMGR command: power control
MOVE.L SP,A0 ; A0 gets pointer to parameter block
_PmgrOp
LEA pmRBuffer+4+2(SP),SP ; Remove stack frame
MOVEA.L PmgrBase,A0 ; get addr of globals <t25>
BCLR.B #HDPowerOn,PmgrFlags(A0) ; clear HD powered on flag <t25>
@NoPMGR RTS
;________________________________________________________________________________________
;
; Routine: PortableCheck
;
; Inputs: D2 - Bits 31..16, hwCfgFlags info (possibly unknown)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
; A1 - Productinfo
;
; Outputs: none
;
; Trashes: D0-D1, A0-A6
;
; Function: Called by a BSR6 from StartInit to check if we're booting
; or waking up. Since we've just called JumpIntoROM, D2
; has the decoder kind.
;________________________________________________________________________________________
beok EQU 27 ;a BusError is expected and is OK (copied from STEqu.a to avoid duplicate label if included)
PortableCheck
IF isUniversal THEN
BTST.L #(hwCbPwrMgr+16),D2 ; Are we running on Pmgr System
BEQ.W NonPwrMgr ; NOPE. Branch...
ENDIF
MOVEA.L A6,A5 ; save return addr <H34>
LEA @NoRAM,A6 ; load return addr in case of bus error <H34>
MOVE.L PmgrBase,A2 ; get the addr of PMgrVars <H34>
CMP.L #SleepConst,SleepSaveFlag(A2) ; are we waking from sleep?
BNE.S @noRAM ; branch if not <H34>
CLR.L SleepSaveFlag(A2) ; clear the sleep flag
MOVE.L WakeVector(A2),A0 ; Go restore ourself
JMP (A0) ; .
NOP ; keep everything aligned <H34>
@NoRAM MOVEA.L A5,A6 ; restore return addr <H34>
;————————————————————————————————————————————————————————————————————————————————
; Routine: CheckEconoMode
;
; Input: D2 - Bits 31..16, hwCfgFlags info (possibly unknown)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
;
; Destroys: A0-A7,D0-D6
;
; Called by: BSR6 from StartInit.
;
; Function: checks to see if a portable needs to be switched into econo-mode
;————————————————————————————————————————————————————————————————————————————————
CheckEconoMode
; do we have a Pratt?
btst #(PrattExists//8),(ProductInfo.BasesValid1+3-(PrattExists/8))(a1)
bne NonPwrMgr ; yes don't do anything
MOVEA.L A6,A7 ; save the return address <H18>
BigBSR6 InitWallyWorld,A1 ; download code into the PMGR, if necessary <H18>
MOVEQ #0,D2 ; <H18>
BigBSR6 GetHardwareInfo,A0 ; figure out what we're running on
MOVE.L D2,D4 ; save the decoder type around the PRAM calls <H18>
MOVEQ #$10,D1 ; read the PRAM validation byte <H18>
MOVEA.L DecoderInfo.VIA1Addr(A0),A2 ; point to base of VIA1 <H19>
BigBSR6 RdXByte,A0 ; <H18>
MOVEQ #$A8-256,D0 ; compare what was read against expected value <H18>
SUB.B D1,D0 ; <H18>
MOVEQ #0,D1 ; (assume PRAM's invalid) <H18>
TST.B D0 ; is PRAM OK? <H18>
BNE.S @BadPRAM ; -> no, run at full speed for now <H18>
MOVEQ #PmgrPramBase+PmgrPramRec.PmgrOtherFlags,D1 ; default to standard PRAM location <H7>
MOVE.L PowerManagerPtr(A1),D0 ; does this box have a PMgr primitives table? <H36><H37>
IF 0 THEN
BEQ.S @UseDefPRAM ; -> no, use the default location <H36>
MOVEA.L A1,A2 ; <H36><H37>
ADDA.L D0,A2 ; point to the primitives table for this box <H36>
ADDA.L PmgrPrimsRec.PrimInfoPtr(A2),A2 ; and then to the primitives info table <H7>
MOVE.B PrimInfoTbleRec.PrimPRAMBase(A2),D1 ; get the base Power Manager PRAM byte <H7>
ADDQ.B #PmgrPramRec.PmgrOtherFlags,D1 ; and adjust for the byte we want <H7>
ENDIF
@UseDefPRAM MOVEA.L A1,A0 ; point back to the DecoderInfo table <H37>
ADDA.L DecoderInfoPtr(A0),A0 ; <H37>
MOVEA.L DecoderInfo.VIA1Addr(A0),A2 ; point to the base of VIA1
BigBSR6 RdXByte,A0 ; read the desired econo-mode setting from PRAM
ANDI.B #(1<<EconoBit),D1 ; and mask off the econo-mode bit
@BadPRAM MOVE.L D4,D2 ; restore the decoder type
MOVEA.L A1,A0 ; point back to the DecoderInfo table <H37>
ADDA.L DecoderInfoPtr(A0),A0 ; one last time <H37>
; at this point:
; A0 - pointer to DecoderInfo table
; A1 - pointer to ProductInfo table
; D2 - decoder type
IF hasJAWS | hasNiagra THEN
;•••••••••••••••••••••••••••••••••••••••••••••• JAWS ••••••••••••••••••••••••••••••••••••••••••••••
SPIN_WAIT equ $40000 ; delay for power manager to hit reset <H23>
SPEED25MHZBIT equ 0 ; 1 = running at 25mhz
IF isUniversal THEN
cmp.b #Decoderkinds.NiagraDecoder,D2 ; Do we have a Niagra decoder? <H14>
beq.s @DoNiagra ; -> yes, go do it.. <H14>
cmp.b #Decoderkinds.JAWSDecoder,D2 ; Do we have a JAWS decoder ?
bne.s NotJaws ; -> no, do next one
ENDIF
IF hasJAWS THEN
@DoJaws MOVEA.L DecoderInfo.JAWSAddr(A0),A1 ; A1 = pointer to the base of the JAWS decoder <H19>
MOVE.L #JAWSGetCPUClock,D0 ; get the offset to the CPU clock frequency register
BTST #SPEED25MHZBIT,0(A1,D0.L) ; are we running at 25MHz?
BEQ.S @JAWSDone ; -> no, done
ENDIF
@DoNiagra MOVEA.L DecoderInfo.JAWSAddr(A0),A1 ; A1 = pointer to the base of the JAWS decoder <H19>
MOVEQ #(1<<EconoBit),D2 ; mask off the econo bit in the econo-mode register
AND.B JAWSEconoMode(A1),D2
CMP.B D1,D2 ; are we currently in the right mode?
BEQ.S @JAWSDone ; -> yes, done
MOVE.B D1,JAWSEconoMode(A1) ; stuff the new mode into the econo register
MOVE.W #(0<<8)+(resetCPU<<0),D3 ; data length=0, command=reset PMGR
BigBSR6 USTPMGRSendCommand,A2 ; reset the system
MOVE.L #SPIN_WAIT,D3 ; wait awhile for the PMGR to reset the system
@spin SUBQ.L #1,D3
BNE.S @spin
@JAWSDone ; <H23>
bra ExitEconoMode ; <H23>
NotJaws
ENDIF
IF hasMSC THEN
;•••••••••••••••••••••••••••••••••••••••••••••• MSC •••••••••••••••••••••••••••••••••••••••••••••••
IF isUniversal THEN
CMPI.B #DecoderKinds.MSCDecoder,D2 ; do we have a MSC decoder?
BNE NotMSC ; -> nope, bail
ENDIF
ORI.B #MSCDefConfig,D1 ; this sets 25Mhz mode by default
; <H45> D2 now has the value of the Econo Mode bit in PRAM. Yeager needs
; to make sure that this bit is never set, or it will break!
MOVEQ #$1F,D2 ; mask off the CPU ID
AND.W CPUIDValue(A1),D2 ;
BEQ.S @MSC33MHz ; is it a new Yeager MBT 040
CMP.W #16,D2 ; is it a Yeager (040)?
BEQ.S @MSC33MHz ; -> yes, do setup
AND.W #7,D2 ; mask off the CPU ID
CMP.W #5,D2 ; is it a 33MHz system (DB Lite)? <H38>
BEQ.S @MSC33MHz ; -> yes, do setup <H38>
CMP.W #2,D2 ; maybe it's a 33MHz Escher? <H38>
BEQ.S @MSC33MHz ; -> yes, do setup <H38>
BTST #EconoBit,D1 ; are we in going to run in econo-mode? <H15>
BNE.S @NotMSC33MHz ; -> yes, we'll be running at 16MHz regardless <H15>
@MSC33MHz BCLR #MSC25MHz,D1 ; setup the state machines to run at 33MHz <H10>
@NotMSC33MHz
MOVEA.L DecoderInfo.RBVAddr(A0),A1 ; point to the base of the MSC decoder
MOVEQ #(%11111000)-256,D2 ; mask off the RAM size information <H15>
AND.B MSCConfig(A1),D2 ; <H15>
OR.B D2,D1 ; and add it to the base configuration <H15>
MOVE.B D1,MSCConfig(A1) ; stuff the configuration into the register <H6>
MOVE.L #(0<<16)|(1<<8)|(SetModemInts<<0),D3 ; <H30>
BigBSR6 USTPmgrSendCommand,A2 ; turn off modem interrupts <H30>
;◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ <H31>
;
; This is the nasty hack. When a DBLite is docked to a Gemini or DeskBar with an external SCSI
; hard disk connected and powered up, the SCC gets charged up a little bit and ends up in a weird
; state, usually generating level 4 interrupts. Normally we initialize the SCC later, but since
; the Docking Manager isn't initialized soon enough, as soon as interrupts are opened up, we get
; stuck in the level 4 interrupt handler (which is hopefully set up). This hack will talk to the
; Gemini/DeskBar hardware directly and reset the external SCC.
ROMSigAddr EQU $FEFFFFE4 ; where to find the ROM signature
ROMSigLo EQU 'Russ' ; and what it is
ROMSigHi EQU 'SWC!'
vscClockPwr EQU $FEE00021 ; VSC power control register
vscSCCclock EQU 1 ; 1=turn on SCC clock
vscSCCAddr EQU $FEE08000 ; SCC base address
NastyHack
If Not ForRomulator Then
MOVEA.L SP,A5 ; save the return address
BSET #beok,D7 ; allow bus errors
BSR6 @WhackSCC ; go whack the SCC (bad SCC! bad SCC! blah blah)
BCLR #beok,D7 ; disallow bus errors
Endif
BRA.S ExitEconoMode
@InitBData DC.B 9,$C0 ; do a hard reset
DC.B 9,$40 ; reset the channel
DC.B 4,$4C ; set async mode (magic?)
DC.B 2,$00 ; zero interrupt vector for dispatcher
DC.B 3,$C0 ; DCD not an auto-enable
DC.B 15,$00 ; no interrupts
DC.B 0,$10 ; reset ext/sts interrupts twice
DC.B 0,$10
DC.B 1,$00 ; no interrupts
@InitAData DC.B 9,$80 ; reset the channel
DC.B 4,$4C ; set async mode (magic?)
DC.B 3,$C0 ; DCD not an auto-enable
DC.B 15,$00 ; no interrupts
DC.B 0,$10 ; reset ext/sts interrupts twice
DC.B 0,$10
DC.B 1,$00 ; no interrupts
@WhackSCC CMPI.L #ROMSigLo,ROMSigAddr ; is the signature in the config ROM?
BNE.S @NotGemini ; -> no, not the ROM we're looking for
CMPI.L #ROMSigHi,ROMSigAddr+4 ; ditto with the other part of the signature
BNE.S @NotGemini ; -> no, not the ROM we're looking for
BSET #vscSCCclock,vscClockPwr ; turn on clocks to the SCC
LEA vscSCCAddr,A0
LEA @InitBData,A2 ; point to channel B init data
MOVEQ #@InitAData-@InitBData,D1
LEA @ResumeB,A1
BRA.S @WriteSCC
@ResumeB ADDQ.W #ACtl,A0 ; point to channel A
MOVEQ #@WhackSCC-@InitAData,D1
LEA @ResumeA,A1
@WriteSCC MOVE.B (A0),D2 ; read to make sure the SCC is sync'ed up
BRA.S @2 ; delay for timing, too
@1 MOVE.L (SP),(SP) ; delay long for reset
MOVE.L (SP),(SP)
MOVE.B (A2)+,(A0)
@2 DBRA D1,@1
JMP (A1)
@ResumeA BCLR #vscSCCclock,vscClockPwr ; turn off clocks to the SCC
@NotGemini RTS6
;◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ <H31>
NotMSC
ENDIF
ExitEconoMode
MOVEA.L A7,A6 ; restore the return address <H23>
;________________________________________________________________________________________
; Routine: InitAndBlankScreen |
; V
; Input: a6 - return address
;
; Destroys: A0-A7,D0-D6
;
; Called by: BSR6 from StartInit.
;
; Function: initialize and blank the screen to meet timing requirements
;________________________________________________________________________________________
InitAndBlankScreen
IF hasNiagra | hasMSC THEN
movea.l a6,a7 ; save original return address
MOVEQ #0,D2 ;
BigBSR6 GetHardwareInfo,A0 ; figure out what we're running on
cmp.b #Decoderkinds.NiagraDecoder,D2 ; Do we have a Niagra decoder?
beq.s @BlankNiagra ; -> yes
cmpi.b #DecoderKinds.MSCDecoder,D2 ; do we have a MSC decoder?
bne @ExitInitAndBlank ; -> no, continue
IF hasMSC THEN ; <H29>
MOVEA.L DecoderInfo.RBVAddr(A0),A2 ; point to the base of the MSC <H29>
BSET #MSCLCDReset,MSCClkCntl(A2) ; turn on clocks to the GSC so we can program it<H29>
BRA.S @TestForGSC ; <H29>
ENDIF ; <H29>
IF hasNiagra THEN
; send command to power manager to blank the screen and delay before talking to the gsc
; D3- [data2] [data1] [length] [command]
; A0- pointer to DecoderInfo
; A6- return address
@BlankNiagra
MOVE.l #($E0<<0) | \ ; Write Pmgr Ram
(03<<8) | \ ; count 3, 2 address + 1 data
(00<<16) | \ ; addrH - $00xxH
($EA<<24),D3 ; addrL - $xxEA
BigBSR6 USTPMGRSendCommand,A2 ; reset the system
move.b #$0A,D3 ; port 4: d[2] = 0 (blank), d[0] = 1 adb inactive
BigBSR5 USTPMgrSendByte,A4 ; and send it
* bra.s @TestForGSC ; <H29>
ENDIF
; test for gsc chip
@TestForGSC MOVEA.L DecoderInfo.VDACAddr(A0),A0 ; point to base of gsc
movea.l a7,a5 ; save return address in case of bus error <H26>
bset.l #beok,d7 ; allow bus errors
bsr6 @checkforGSC ; check for gsc chip
bra @ExitInitAndBlank ; if not zero, buserror, no gsc, exit
; bne @ExitInitAndBlank ; if not zero, buserror, no gsc, exit
; initialize GSC early to meet hardware timing spec
@loadSetup
moveq.l #7,D0 ; mask off the display ID
And.b GSCPanelID(A0),D0 ; get the display id
MULU #(GSCPanelSkew-GSCPanelSetup+1)+(GSCDiag2-GSCDiag0+1),D0 ;
LEA @GSCInitTable,A2 ; point to the entry for this display
ADDA.L D0,A2
ADDQ.W #GSCPanelSetup,A0 ; point to the first register to blast <H25>
MOVE.L (A2)+,(A0)+ ; initialize the main display registers <H25>
MOVE.L (A2)+,(A0)+ ; <H25>
LEA GSCDiag0-GSCPanelSkew-1(A0),A0 ; point to the diagnostic registers <H25>
MOVE.B (A2)+,(A0)+ ; and initialize them too <H25>
MOVE.W (A2)+,(A0)+ ; <H25>
bra.s @ExitInitAndBlank ; done
@checkforGSC
move.b GSCPanelID(A0),D0 ; try reading a register
moveq #0,d0 ; set CC to Equal, buserr will return not Equal <H26>
rts6
; GSC initialization table. Each entry is based on the LCD panel ID.
;
; panel gray poly panel ACD refresh blank panel
; setup scale adjust adjust clock rate shade skew diag0 diag1 diag2
@GSCInitTable
DC.B $10, $00, $64, $00, $80, $02, $00, $A0, $00, $00, $03 ; ID=0 TFT1Bit <H27>
DC.B $12, $00, $64, $00, $80, $02, $00, $FF, $00, $00, $03 ; ID=1 TFT3Bit <H27>
DC.B $10, $00, $64, $00, $80, $02, $00, $FF, $00, $00, $03 ; ID=2 TFT4Bit <H27>
DC.B $10, $00, $64, $00, $80, $02, $00, $A0, $00, $00, $03 ; ID=3 NotAssignedTFT <H27>
DC.B $10, $00, $64, $00, $80, $05, $00, $A0, $00, $00, $03 ; ID=4 NotAssignedSTN <H27>
DC.B $10, $00, $64, $00, $80, $05, $00, $A0, $00, $00, $03 ; ID=5 TimSTN <H27>
DC.B $10, $00, $63, $00, $80, $05, $00, $9C, $00, $00, $03 ; ID=6 DBLiteSTN <H29>
DC.B $10, $00, $64, $00, $80, $05, $00, $A0, $00, $00, $03 ; ID=7 No Display <H27>
@ExitInitAndBlank
bclr.l #beok,d7 ; disallow bus errors
movea.l a7,a6 ; restore original return address
ENDIF ; {hasNiagra | hasMSC}
;________________________________________________________________________________________
; Routine: Exit
;________________________________________________________________________________________ ; V
NonPwrMgr RTS6 ; return to start init <H23> ; All done
;•••••••••••••••••••••••••••••••••••• End of Misc. •••••••••••••••••••••••••••••••••••••••••••••••••
;•••••••••••••••••••••••••••••••• Public Power Manager •••••••••••••••••••••••••••••••••••••••••••••
;
; Contains:
;
;________________________________________________________________________________________
;________________________________________________________________________________________
;
; Routine: PowerMgrDispatch (trap $A09E)
;
; Inputs: D0 - selector
;
; Outputs: D0 - selector result, or error code if bad selector
;
; Trashes: varies by selector
;
; Function: This is the Power Manager's public dispatch trap, which provides a variety of
; miscellaneous functions to the public, hackers, etc.
;
; NOTE: The offset-based dispatch table is copied into RAM and converted to
; absolute addresses by InitPMgrVars.
;________________________________________________________________________________________
PowerMgrDispatch
MOVEA.L PMgrBase,A2 ; point to the Power Manager's globals
MOVE.L vPublicDispatch(A2),A1 ; and then to the public dispatch table
CMP.W -2(A1),D0 ; is the selector in range?
BHS.S @OutOfRange ; -> no, bail with an error
MOVEA.L 0(A1,D0.W*4),A1 ; point to the routine <H93>
JMP (A1) ; and call it
@OutOfRange MOVEQ #paramErr,D0 ; abort and return error
RTS
ALIGN 4
DC.W 0 ; flags
DC.W (PwrMgrDispEnd-PwrMgrDispVects)/4 ; number of table entries
PwrMgrDispVects
DC.L PMSelectorCount-PwrMgrDispVects ; [ 0] return the number of selectors supported
DC.L PMFeatures-PwrMgrDispVects ; [ 1] return bitmap of Power Manager features
DC.L GetSleepTimeout-PwrMgrDispVects ; [ 2] get the sleep timeout
DC.L SetSleepTimeout-PwrMgrDispVects ; [ 3] set the sleep timeout
DC.L GetHardDiskTimeout-PwrMgrDispVects ; [ 4] get the hard disk spindown timeout
DC.L SetHardDiskTimeout-PwrMgrDispVects ; [ 5] set the hard disk spindown timeout
DC.L HardDiskPowered-PwrMgrDispVects ; [ 6] returns true if hard disk is powered up
DC.L SpinDownHardDisk-PwrMgrDispVects ; [ 7] spin down the hard disk
DC.L IsSpindownDisabled-PwrMgrDispVects ; [ 8] returns whether or not spindown is disabled
DC.L SetSpindownDisable-PwrMgrDispVects ; [ 9] enables/disables hard disk spindown
DC.L HardDiskQInstall-PwrMgrDispVects ; [10] add element to HD queue
DC.L HardDiskQRemove-PwrMgrDispVects ; [11] remove element from HD queue
DC.L ScaledBattery-PwrMgrDispVects ; [12] return the scaled battery level
DC.L AutoSleepControl-PwrMgrDispVects ; [13] enables/disables auto sleep
DC.L GetIntModemInfo-PwrMgrDispVects ; [14] return information about an internal modem
DC.L SetIntModemState-PwrMgrDispVects ; [15] sets the state of the internal modem
DC.L MaximumProcessorSpeed-PwrMgrDispVects ; [16] return maximum processor speed
DC.L CurrentProcessorSpeed-PwrMgrDispVects ; [17] return current processor speed
DC.L FullProcessorSpeed-PwrMgrDispVects ; [18] returns true if processor running at full speed
DC.L SetProcessorSpeed-PwrMgrDispVects ; [19] set full/reduced processor speed
DC.L GetSCSIDiskModeAddress-PwrMgrDispVects ; [20] get SCSI Disk Mode HD address
DC.L SetSCSIDiskModeAddress-PwrMgrDispVects ; [21] set SCSI Disk Mode HD address
DC.L GetWakeupTimer-PwrMgrDispVects ; [22] get wakeup time
DC.L SetWakeupTimer-PwrMgrDispVects ; [23] set wakeup time
DC.L GetProcessorCycling-PwrMgrDispVects ; [24] get processor cycling state
DC.L SetProcessorCycling-PwrMgrDispVects ; [25] set processor cycling state
DC.L BatteryCount-PwrMgrDispVects ; [26] returns number of internal batteries
DC.L GetBatteryVoltage-PwrMgrDispVects ; [27] return absolute battery voltage
DC.L GetBatteryTimes-PwrMgrDispVects ; [28] returns information about battery times
DC.L GetDimTimeout-PwrMgrDispVects ; [29] get the dimming timeout
DC.L SetDimTimeout-PwrMgrDispVects ; [30] set the dimming timeout
DC.L DimControl-PwrMgrDispVects ; [31] enables/disables dimming
DC.L IsDimmingDisabled-PwrMgrDispVects ; [32] returns whether or not dimming is disabled
DC.L IsAutoSlpDisabled-PwrMgrDispVects ; [33] returns whether or not autosleep is disabled
PwrMgrDispEnd
;________________________________________________________________________________________
;
; Routine: PMSelectorCount (PowerMgrDispatch selector #0)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - number of selectors
;
; Trashes: A0
;
; Function: returns the number of selectors so users can determine what selectors are
; supported
;________________________________________________________________________________________
PMSelectorCount
MOVEQ #0,D0
MOVE.L vPublicDispatch(A2),A0 ; point to the public dispatch table
MOVE.W -(A0),D0 ; and get the number of selectors
RTS
;________________________________________________________________________________________
;
; Routine: PMFeatures (PowerMgrDispatch selector #1)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - bitmap of supported features
;
; Trashes: none
;
; Function: returns a bitmap containing bits describing which software/hardware
; features are supported on this machine
;________________________________________________________________________________________
PMFeatures
LoadTbl PrimInfoTblPtr,A2,A0 ; get pointer to Info
MOVE.L PrimPubFeatures(A0),D0 ; get the features bits
RTS
;________________________________________________________________________________________
;
; Routine: GetSleepTimeout (PowerMgrDispatch selector #2)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - sleep timeout (number of 15 second intervals)
;
; Trashes: A0
;
; Function: returns the current sleep timeout time
;________________________________________________________________________________________
GetSleepTimeout
MOVEQ #SlpTimeOut,D0 ; which byte to read
BRA.S ReadPMgrPRAM ; go read and return the value
;________________________________________________________________________________________
;
; Routine: SetSleepTimeout (PowerMgrDispatch selector #3)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: sleep time to set (number of 15 second intervals)
;
; Outputs: D0 - result code (always zero)
;
; Trashes: D1, A0
;
; Function: sets the current sleep timeout
;________________________________________________________________________________________
SetSleepTimeout
SWAP D0 ; get the new value
TST.B D0 ; is it zero?
BNE.S @NotZero ; -> no
MOVEQ #DfltSlpTime,D0 ; yes, set it to the default
@NotZero
MOVE.B D0,SleepTime(A2) ; save it
MOVE.B D0,D1
MOVEQ #SlpTimeOut,D0 ; where to put it
BRA.S WritePMgrPRAM ; go write it out
;________________________________________________________________________________________
;
; Routine: GetHardDiskTimeout (PowerMgrDispatch selector #4)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - hard disk time (number of 15 second intervals)
;
; Trashes: A0
;
; Function: returns the amount of time the system will wait after the last hard disk
; access before shutting down power to the hard disk
;________________________________________________________________________________________
GetHardDiskTimeout
MOVEQ #HDTimeOut,D0 ; which byte to read
; Inputs: D0 - PRAM address (upper word must be zero)
;
; Outputs: D0 - byte read from PRAM
;
; Trashes: D0
ReadPMgrPRAM
ADD.B PRAMBase(A2),D0 ; get the absolute PRAM address
SWAP D0
ADDQ.W #1,D0 ; one byte
SWAP D0
CLR.W -(SP) ; make space for a buffer on the stack
MOVEA.L SP,A0 ; and point to it
_ReadXPRAM ; read the byte
MOVEQ #0,D0
MOVE.B (SP)+,D0 ; and return it in D0
RTS
;________________________________________________________________________________________
;
; Routine: SetHardDiskTimeout (PowerMgrDispatch selector #5)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: hard disk time to set (number of 15 second intervals)
;
; Outputs: D0 - result code (always zero)
;
; Trashes: D1, A0
;
; Function: sets the amount of time the system will wait after the last hard disk
; access before shutting down power to the hard disk
;________________________________________________________________________________________
SetHardDiskTimeout
SWAP D0 ; get the new value
TST.B D0 ; is it zero?
BNE.S @NotZero ; -> no
MOVEQ #DfltHDTime,D0 ; yes, set it to the default
@NotZero
MOVE.B D0,HDTime(A2) ; save it
MOVE.B D0,D1
MOVEQ #HDTimeOut,D0 ; where to put it
; Inputs: D0 - PRAM address (upper word must be zero)
; D1 - byte to write
;
; Outputs: D0 - none
;
; Trashes: D0
WritePMgrPRAM
MOVE.B D1,-(SP) ; push the byte to write
MOVEA.L SP,A0 ; and point to it
ADD.B PRAMBase(A2),D0 ; get the absolute PRAM address
SWAP D0
ADDQ.W #1,D0 ; one byte
SWAP D0
_WriteXPRAM ; write the byte
ADDQ.W #2,SP
ST TODirtyFlag(A2) ; force an update of the new values
RTS
;________________________________________________________________________________________
;
; Routine: HardDiskPowered (PowerMgrDispatch selector #6)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - 1=hard disk spinning, 0=hard disk powered down
;
; Trashes: A2
;
; Function: spins down the internal hard disk immediately
;________________________________________________________________________________________
HardDiskPowered
MOVEQ #0,D0 ; zero-extend the result
TST.L LastHd(A2) ; is the hard disk powered up?
SNE D0 ; $FF if so, $00 if not
NEG.B D0 ; 1 if so, 0 if not
RTS
;________________________________________________________________________________________
;
; Routine: SpinDownHardDisk (PowerMgrDispatch selector #7)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - result code (always zero)
;
; Trashes: A0
;
; Function: spins down the internal hard disk immediately
;________________________________________________________________________________________
SpinDownHardDisk
_SpinDownHardDrive
MOVEQ #0,D0
@Done RTS
;________________________________________________________________________________________
;
; Routine: IsSpindownDisabled (PowerMgrDispatch selector #8)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - boolean: 1=disabled, 0=enabled
;
; Trashes: none
;
; Function: returns a boolean telling whether hard disk spindown is enabled or disabled
;________________________________________________________________________________________
IsSpindownDisabled
MOVEQ #0,D0
IF HDSpinDownDisable=7 THEN
TST.B PmgrFlags2(A2)
SMI D0
ELSE
BTST #HDSpinDownDisable,PmgrFlags2(A2)
SNE D0
ENDIF
NEG.B D0
RTS
;________________________________________________________________________________________
;
; Routine: SetSpindownDisable (PowerMgrDispatch selector #9)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: 1=disable, 0=enable
;
; Outputs: D0 - result code (always zero)
;
; Trashes: none
;
; Function: enables or disables hard disk spindown
;________________________________________________________________________________________
SetSpindownDisable
SWAP D0
TST.B D0 ; is it to be disabled?
BNE.S @disable ; -> yes
BCLR #HDSpinDownDisable,PmgrFlags2(A2)
BRA.S @Done ; no, enable it
@disable BSET #HDSpinDownDisable,PmgrFlags2(A2)
@Done MOVEQ #0,D0
RTS
;________________________________________________________________________________________
;
; Routine: HardDiskQInstall (PowerMgrDispatch selector #10)
;
; Inputs: A0 - pointer to queue element
; A2 - pointer to Power Manager globals
;
; Outputs: D0 - result code (always zero)
;
; Trashes: A0, A1, D0
;
; Function: adds an element to the hard disk spindown notification queue
;________________________________________________________________________________________
HardDiskQInstall
MOVEQ #slpTypeErr,D0 ; assume bad queue type
CMP.W #HDPwrQType,hdQType(A0) ; is it?
BNE.S @Done ; -> yes, bail
LEA HardDiskQHdr(A2),A1 ; point to the hard disk queue
_Enqueue ; and add the element to the queue
MOVEQ #0,D0 ; <H87>
@Done RTS
;________________________________________________________________________________________
;
; Routine: HardDiskQRemove (PowerMgrDispatch selector #11)
;
; Inputs: A0 - pointer to queue element
; A2 - pointer to Power Manager globals
;
; Outputs: D0 - result code
;
; Trashes: A0, A1, D0
;
; Function: removes an element from the hard disk spindown notification queue
;________________________________________________________________________________________
HardDiskQRemove
MOVEQ #slpTypeErr,D0 ; assume bad queue type
CMP.W #HDPwrQType,hdQType(A0) ; is it?
BNE.S @Done ; -> yes, bail
LEA HardDiskQHdr(A2),A1 ; point to the hard disk queue
_Dequeue ; and remove the element from the queue
MOVEQ #0,D0 ; <H87>
@Done RTS
;________________________________________________________________________________________
;
; Routine: AutoSleepControl (PowerMgrDispatch selector #13)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: 0=disable sleep, 1=enable sleep
;
; Outputs: D0 - result code (always zero)
;
; Trashes: A0
;
; Function: Disables or enables auto sleep by incrementing or decrementing the auto sleep
; semaphone. Note that since the semaphore supports multiple levels, if it's
; been disabled n times in a row, it needs to be enabled n times before auto
; sleep will really be enabled.
;________________________________________________________________________________________
AutoSleepControl
SWAP D0 ; get the flag <H85>
TST.W D0 ; enable or disable? <H85>
BEQ.S @disable ; -> disable <H85>
SUBQ.B #1,AutoSlpDisable(A2) ; pop a level towards sleep enabled <H85>
BGE.S @done ; -> haven't rolled over <H85>
CLR.B AutoSlpDisable(A2) ; pin the semaphore a zero <H85>
BRA.S @done ; <H85>
@disable ADDQ.B #1,AutoSlpDisable(A2) ; set the semaphore to >0 (push a level) <H85>
BHI.S @done ; -> we're done if it's still >0 <H85>
SUBQ.B #1,AutoSlpDisable(A2) ; it rolled over, so make it >0 again <H85>
@done MOVEQ #0,D0 ; <H85>
RTS ; <H85>
;________________________________________________________________________________________
;
; Routine: GetIntModemInfo (PowerMgrDispatch selector #14)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - bitmap of internal modem info:
; 0: 1=modem installed
; 1: 1=modem ring detected
; 2: 1=modem off hook
; 3: 1=wakeup on ring is enabled
; 4: 1=external modem selected
; 15-3: 0=reserved
; 31-16: modem type
; -1 = modem installed but type unknown
; 0 = no modem installed
; 1 = original serial modem
; 2 = Rockwell data pump modem (RC144DPL)
; 3 = Rockwell data pump modem (RC144DPL) + 6805 controller
;
; Trashes: A0
;
; Function: returns a bitmap of information about the internal modem, if any
;________________________________________________________________________________________
GetIntModemInfo
CLR.W -(SP) ; allocate a buffer for the result
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength
MOVE.W #modemRead,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; get the modem info
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVEQ #PmgrStatusFlags,D0 ; read the byte containing modem status <H83>
BSR ReadPMgrPRAM ; <H83>
MOVEQ #1<<UseIntrnlModem,D1 ; mask off the bit, <H83>
AND.B D0,D1 ; <H83>
LSL.B #extModemSelected-UseIntrnlModem,D1 ; and shift it into position <H95>
MOVEQ #(1<<RingWakeEnable)|(1<<ModemInstalled)|(1<<RingDetect)|(1<<ModemHook),D0 ; <H95>
AND.B (SP)+,D0 ; mask off the bits we want, <H83>
ROR.B #ModemInstalled-hasInternalModem,D0 ; <H94>
; and shift them into position <H83>
BCLR #8-(ModemInstalled-hasInternalModem)+RingWakeEnable,D0 ; <H94>
BEQ.S @NoWake ; -> the wakeup on ring bit isn't set <H94>
ADDQ.B #1<<intModemRingWakeEnb,D0 ; set the bit in the output <H94>
@NoWake OR.B D1,D0 ; combine all the bits so far <H83>
BTST #hasInternalModem,D0 ; is an internal modem installed? <H93>
BEQ.S @Done ; -> no, we're done <H93>
MOVE.L D0,-(SP) ; save the rest of the information <H93>
BSR ModemTypeProc ; find out what kind of modem is installed <H93>
SWAP D0 ; and move it into bits 16-31 <H93>
CLR.W D0 ; (make sure we don't have any stray bits) <H93>
OR.L (SP)+,D0 ; then OR in the rest of the info <H93>
@Done RTS
;________________________________________________________________________________________ <H95>
;
; Routine: SetIntModemState (PowerMgrDispatch selector #15)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: bitmap of bits to set or clear
; 18: 1=wakeup on ring is enabled if bit 31=1, or disabled if bit 31=0
; 19: 1=external modem selected if bit 31=1, or external if bit 31=0
; 31: 1=set all other 1-bits, 0=clear all other 1-bits
;
;
; Outputs: D0 - result code (always zero)
;
; Trashes: A0
;
; Function: Configures some of the state information for the internal modem.
;________________________________________________________________________________________
SetIntModemState
SWAP D0 ; get the flags
BTST #intModemRingWakeEnb,D0 ; do we need to update wakeup on ring?
BEQ.S @NoWake ; -> nope
LoadTbl PrimInfoTblPtr,A2,A0
MOVE.L PrimPubFeatures(A0),D1 ; does this machine support wakeup on ring?
BTST #canWakeupOnRing,D1
BEQ.S @NoWake ; -> no, skip it
MOVE.W D0,-(SP) ; save the flags
SMI D0 ; $FF=enabled, $00=disabled
MOVEQ #1<<RingWakeEnable,D1 ; mask off the wakeup on ring bit
AND.L D0,D1
CLR.W -(SP) ; allocate a buffer for the result
MOVE.L SP,-(SP) ; pmRBuffer
MOVE.L (SP),-(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength
MOVE.W #modemRead,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; get the modem info
ANDI.B #~(1<<RingWakeEnable),pmRBuffer+4(SP) ; mask out the wakeup on ring bit
OR.B D1,pmRBuffer+4(SP) ; and OR in the new value
MOVE.W #modemSet,pmCommand(SP)
_PMgrOp ; write it back out
LEA pmRBuffer+4(SP),SP ; toss the parameter block
MOVE.W (SP)+,D0 ; get the flags back
@NoWake BTST #extModemSelected,D0 ; do we need to update internal/external modem?
BEQ.S @Done ; -> nope, all done
TST.W D0 ; test for zero/non-zero
SMI -(SP) ; push $00=internal/$FF=external on stack
MOVEQ #PmgrStatusFlags,D0 ; read the byte containing modem status
BSR ReadPMgrPRAM
MOVEQ #~(1<<UseIntrnlModem),D1 ; mask off everything but the modem bit
AND.B D0,D1
MOVEQ #1<<UseIntrnlModem,D0 ; mask off the passed in flag
AND.B (SP)+,D0
OR.B D0,D1 ; and OR it in with the other bits
MOVE.B D1,SleepFlags(A2) ; save it
MOVEQ #PmgrStatusFlags,D0 ; write the byte containing modem status back out
BRA WritePMgrPRAM
@Done RTS
;________________________________________________________________________________________
;
; Routine: MaximumProcessorSpeed (PowerMgrDispatch selector #16)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - processor speed
;
; Trashes: D1, A0
;
; Function: returns the maximum processor speed, in MHz
;________________________________________________________________________________________
MaximumProcessorSpeed
MOVEQ #CPUSpeedDisp,D0 ; get the current/max CPU speed
_PowerDispatch
CLR.W D0 ; clear the current speed
SWAP D0 ; and move the max speed into the lower word
RTS
;________________________________________________________________________________________
;
; Routine: CurrentProcessorSpeed (PowerMgrDispatch selector #17)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - processor speed
;
; Trashes: D1, A0
;
; Function: returns the current processor speed, in MHz
;________________________________________________________________________________________
CurrentProcessorSpeed
MOVEQ #CPUSpeedDisp,D0 ; get the current/max CPU speed
_PowerDispatch
EXT.L D0 ; clear the maximum speed speed
RTS
;________________________________________________________________________________________
;
; Routine: FullProcessorSpeed (PowerMgrDispatch selector #18)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - boolean: 1=full speed, 0=reduced speed
;
; Trashes: D1, A0
;
; Function: returns a boolean indicating whether the CPU will start up at full or
; reduced speed
;________________________________________________________________________________________
FullProcessorSpeed
MOVEQ #1,D0 ; assume full speed <H92>
LoadTbl PrimInfoTblPtr,A2,A0
MOVEQ #1<<hasReducedSpeed,D1 ; is reduced speed supported? <H92>
AND.L PrimPubFeatures(A0),D1 ; <H92>
BEQ.S @Done ; -> no, we're done <H92>
MOVEQ #PmgrOtherFlags,D0 ; read the byte containing the CPU speed bit
BSR.S ReadPMgrPRAM
IF EconoBit≠0 THEN
LSR.B #EconoBit,D0 ; shift the bit into bit zero
ENDIF
MOVEQ #1,D1
EOR.B D1,D0 ; invert the bit so true=full speed
AND.B D1,D0 ; and mask off the bit
@Done RTS
;________________________________________________________________________________________
;
; Routine: SetProcessorSpeed (PowerMgrDispatch selector #19)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: 1=full speed, 0=half speed
;
; Outputs: D0 - boolean: true=speed was changed, false=only PRAM was changed
;
; Trashes: D1, D2, A0, A1, A2
;
; Function: Updates PRAM to reflect the desired CPU speed on the next restart. If the
; machine supports dynamic speed switching, the hardware will be whacked to
; change the speed, the low-mem timing constants (TimeDBRA, etc.) will be
; updated, and the AppleTalk Transition Queue will be run to notify anyone
; who cares that they need to recalculate their timing parameters.
;________________________________________________________________________________________
ATQEntry RECORD 0,INCREMENT
qLink DS.L 1 ; pointer to next queue entry
qType DS.W 1 ; queue type
CallAddr DS.L 1 ; pointer to routine to be called
ENDR
ATTransSpeedChange EQU 'sped' ; event = speed change
SetProcessorSpeed
SWAP D0 ; get the boolean,
MOVEQ #1,D1
EOR.B D1,D0 ; invert it so true=reduced speed,
AND.B D0,D1 ; mask it off to a single bit,
IF EconoBit=1 THEN
ADD.B D1,D1 ; and then shift it into the correct bit position
ELSEIF EconoBit>1
LSL.B #EconoBit,D1 ; and then shift it into the correct bit position
ENDIF
MOVEQ #1,D0 ; assume full speed <H92>
LoadTbl PrimInfoTblPtr,A2,A0
MOVEQ #1<<hasReducedSpeed,D2 ; is reduced speed supported? <H92>
AND.L PrimPubFeatures(A0),D2 ; <H92>
BEQ @Done ; -> no, we're done <H92>
; update the setting in PRAM
MOVEQ #PmgrOtherFlags,D0 ; read the byte containing the CPU speed bit
BSR.S ReadPMgrPRAM
MOVE.B D0,D2
ANDI.B #~(1<<EconoBit),D0 ; mask out the econo-mode bit
OR.B D0,D1 ; and insert the new value into the byte
MOVEQ #0,D0
CMP.B D2,D1 ; will the speed change?
BEQ @Done ; -> no, just exit
MOVEQ #PmgrOtherFlags,D0 ; yes, write the PRAM byte back out
BSR.S WritePMgrPRAM
MOVEQ #1<<EconoBit,D0 ; mask off the econo-mode bit
AND.W D0,D1
; change the speed if it can be done dynamically
LoadTbl PrimInfoTblPtr,A2,A0
MOVEQ #1<<dynamicSpeedChange,D0 ; is dynamic speed change supported? <H90>
AND.L PrimPubFeatures(A0),D0 ; <H90>
BEQ.S @Done ; -> no, we're done <H90>
MOVE.W D1,-(SP) ; (save D1 across the call)
JsrRoutine SpeedChangePtr,A2,A0 ; and go do the switch
MOVE.W (SP)+,D1 ; (restore D1)
TST.W D0 ; did we do the speed switch?
BEQ.S @Done ; -> no, we're done
MOVEQ #CPUSpeedDisp,D0 ; get the current CPU speed
_PowerDispatch
MOVE.B D0,saveSpeedo(A0) ; and update speedo for people using IdleRead
; setup new timing constants for the TimeDBRA low-mems
LSL.W #3-EconoBit,D1 ; convert D1 to an index (0 or 8)
LEA fullSpeedDBRAs(A2),A1 ; point to the correct table
ADDA.W D1,A1
MOVE.W (A1)+,TimeDBRA ; copy the timing constants to low mem
MOVE.W (A1)+,TimeSCCDB
MOVE.W (A1)+,TimeSCSIDB
MOVE.W (A1)+,TimeVIADB
; run the AppleTalk transition queue
MOVE.L #gestaltAppleTalkVersion,D0 ; get the version of AppleTalk
_Gestalt
BNE.S @NoATalk ; -> error means it's not installed
MOVE.L A0,D0 ; get the AppleTalk version
BEQ.S @NoATalk ; -> zero means AppleTalk is turned off
MOVEQ #25,D0 ; get a pointer to the transition queue
MOVEA.L AtalkHk2,A0
JSR LapMgrCall(A0)
LEA qHead(A1),A2 ; point to the head of the queue
BRA.S @StartQueue
@NextQueue MOVE.L D0,A2 ; point to the queue element
MOVEM.L D3-D7/A2-A6,-(SP) ; save registers cuz apparently some procs do trash them
CLR.L -(SP) ; no routine-specific parameters
MOVE.L A2,-(SP) ; *ATQEntry
PEA ATTransSpeedChange ; selector = speed change
MOVEA.L ATQEntry.CallAddr(A2),A0 ; call the transition queue element's routine
JSR (A0)
LEA 4+4+4(SP),SP ; toss the parameters
MOVEM.L (SP)+,D3-D7/A2-A6
@StartQueue MOVE.L qLink(A2),D0 ; point to the next queue element; end of the queue?
BNE.S @NextQueue ; -> no, keep looping
@NoATalk MOVEQ #1,D0
@Done RTS
;________________________________________________________________________________________
;
; Routine: GetSCSIDiskModeAddress (PowerMgrDispatch selector #20)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - SCSI bus addresse internal hard disk (1-6)
;
; Trashes: D1, A0
;
; Function: returns the SCSI Disk Mode address of the internal hard disk
;________________________________________________________________________________________
GetSCSIDiskModeAddress
LoadTbl PrimInfoTblPtr,A2,A0
MOVEQ #1<<hasSCSIDiskMode,D0 ; is SCSI Disk Mode supported on this machine?
AND.L PrimPubFeatures(A0),D0
BEQ.S @Done
MOVEQ #PmgrOtherFlags,D0 ; read the byte containing the address
BSR.S ReadPMgrPRAM
IF DiskModeAddr≠0 THEN
LSR.B #DiskModeAddr,D0 ; and shift it down to bit zero
ENDIF
IF DiskModeAddr<5 THEN
ANDI.B #%111,D0 ; mask to just the 3 lsb's
ENDIF
MOVE.B mapSCSIAddr(D0),D0 ; make sure we return a valid address
@Done RTS
mapSCSIAddr DC.B 2,1,2,3,4,5,6,2 ; <H94>
;________________________________________________________________________________________
;
; Routine: SetSCSIDiskModeAddress (PowerMgrDispatch selector #21)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: SCSI bus address of the internal hard disk (1-6)
;
; Outputs: D0 - result code (always zero)
;
; Trashes: D0, D1, A0
;
; Function: updates PRAM with the SCSI Disk Mode address for the internal hard disk
;________________________________________________________________________________________
SetSCSIDiskModeAddress
LoadTbl PrimInfoTblPtr,A2,A0
MOVEQ #1<<hasSCSIDiskMode,D1 ; is SCSI Disk Mode supported on this machine?
AND.L PrimPubFeatures(A0),D1
BEQ.S @Done
SWAP D0 ; get the ID
CMPI.W #7,D0 ; is it in range?
BLS.S @MapID ; -> yes
MOVEQ #7,D0 ; no, pin it
@MapID MOVE.B mapSCSIAddr(D0),D0 ; make sure the address is valid,
IF DiskModeAddr≠0 THEN
LSL.B #DiskModeAddr,D0 ; and then shift it into the correct bit position
ENDIF
MOVE.B D0,D1 ; save it for the write
MOVEQ #PmgrOtherFlags,D0 ; read the byte containing the CPU speed bit
BSR ReadPMgrPRAM
ANDI.W #~(%111<<DiskModeAddr),D0 ; mask out the disk mode address bits
OR.B D0,D1 ; and insert the new value into the byte
MOVEQ #PmgrOtherFlags,D0 ; then write the PRAM byte back out
BRA WritePMgrPRAM
@Done MOVEQ #0,D0
RTS
;________________________________________________________________________________________
;
; Routine: GetWakeupTimer (PowerMgrDispatch selector #22)
;
; Inputs: A0 - pointer to buffer to hold wakeup time and enable/disable flag byte
; A2 - pointer to Power Manager globals
;
; Outputs: D0 - none
;
; Trashes: A0,A1
;
; Function: returns the time when the PowerBook will wake up
;________________________________________________________________________________________
GetWakeupTimer
LoadTbl PrimInfoTblPtr,A2,A1
MOVEQ #1<<hasWakeupTimer,D0 ; does this machine have a wakeup timer?
AND.L PrimPubFeatures(A1),D0
BEQ.S @NoTimer ; -> no, we're done
MOVE.L A0,-(SP) ; pmRBuffer <H95>
CLR.L -(SP) ; pmSBuffer
CLR.W -(SP) ; pmLength
MOVE.W #timerRead,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; read the wakeup time
LEA pmRBuffer+4(SP),SP ; toss the parameter block
RTS
@NoTimer CLR.L (A0)+ ; zero out all the fields <H95>
CLR.B (A0)+ ; <H95>
RTS ; <H95>
;________________________________________________________________________________________
;
; Routine: SetWakeupTimer (PowerMgrDispatch selector #23)
;
; Inputs: A0 - pointer to buffer that contains the wakeup time and enable/disable flag byte
; A2 - pointer to Power Manager globals
;
; Outputs: D0 - none
;
; Trashes: D0,A0,A1
;
; Function: sets the time when the PowerBook will wake up
;________________________________________________________________________________________
SetWakeupTimer
LoadTbl PrimInfoTblPtr,A2,A1
MOVEQ #1<<hasWakeupTimer,D0 ; does this machine have a wakeup timer?
AND.L PrimPubFeatures(A1),D0
BEQ.S @NoTimer ; -> no, we're done
MOVEA.L A0,A1 ; save a copy of the buffer pointer
CLR.L -(SP) ; pmRBuffer <H95>
MOVE.L A0,-(SP) ; pmSBuffer <H95>
MOVE.W #4,-(SP) ; pmLength
MOVE.W #timerSet,-(SP) ; pmCommand
MOVEA.L SP,A0 ; point to the parameter block
_PMgrOp ; set the timer
TST.B 4(A1) ; is the timer to be disabled? <H95>
BNE.S @Done ; -> nope, all done
MOVE.W #$82,pmCommand(A0) ; send a disable wakeup timer command <H95>
CLR.W pmLength(A0) ; <H95>
_PMgrOp ; <H95>
@Done LEA pmRBuffer+4(SP),SP ; clean up the stack
@NoTimer RTS
;________________________________________________________________________________________ <H90>
;
; Routine: GetProcessorCycling (PowerMgrDispatch selector #24)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - boolean: 1=cycling is enabled, 0=cycling is disabled
;
; Trashes: A0
;
; Function: returns whether or not processor cycling is enabled
;________________________________________________________________________________________
GetProcessorCycling
MOVEQ #PmgrStatusFlags,D0 ; read the byte containing modem status <H85>
BSR ReadPMgrPRAM ; <H85>
BTST #IdleBit,D0 ; 1=disabled, 0=enabled
SEQ D0
NEG.B D0 ; 1=enabled, 0=disabled
RTS
;________________________________________________________________________________________ <H90>
;
; Routine: SetProcessorCycling (PowerMgrDispatch selector #25)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - boolean: 1=enable cycling, 0=disable cycling
;
; Outputs: none
;
; Trashes: A0
;
; Function: enables/disables processor cycling
;________________________________________________________________________________________
SetProcessorCycling
SWAP D0 ; get the boolean
TST.W D0 ; enable or disable?
BNE.S @enable
BSET #IdleBit,SleepFlags(A2) ; disable idle
BRA.S @common
@enable BCLR #IdleBit,SleepFlags(A2) ; enable idle
@common MOVEQ #PmgrStatusFlags,D0 ; write the byte containing idle status
MOVE.B SleepFlags(A2),D1
BRA WritePMgrPRAM
;________________________________________________________________________________________ <H90>
;
; Routine: BatteryCount (PowerMgrDispatch selector #26)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - number of internal batteries we can have
;
; Trashes: A0
;
; Function: returns the number of internal batteries we can have
;________________________________________________________________________________________
BatteryCount
MOVEA.L PMgrBase,A2 ; get pointer to Power manager globals
LoadTbl PrimInfoTblPtr,A2,A0
MOVEQ #0,D0 ; get the number of internal batteries we can have
MOVE.W PrimBatteryCount(A0),D0
RTS
;________________________________________________________________________________________ <H83>
;
; Routine: GetBatteryVoltage (PowerMgrDispatch selector #27)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: battery number (0-n)
;
; Outputs: D0 - battery voltage
;
; Trashes: A0-A1, D1-D2
;
; Function: returns the battery voltage as a fixed-point number so that nobody external
; to the Power Manager needs to do the calculation anymore.
;________________________________________________________________________________________
GetBatteryVoltage
MOVEA.L PMgrBase,A2 ; get pointer to Power manager globals
LoadTbl PrimInfoTblPtr,A2,A0
SWAP D0 ; get the battery number <H90>
CMP.W PrimBatteryCount(A0),D0 ; do we support this many batteries? <H90>
BHS.S @NoBattery ; -> no, return zero <H90>
JmpRoutine AbsoluteBattPtr,A2,A0; run the routine
@NoBattery MOVEQ #0,D0 ; return zero volts <H90>
RTS ; <H90>
;________________________________________________________________________________________ <H90>
;
; Routine: GetBatteryTimes (PowerMgrDispatch selector #28)
;
; Inputs: A2 - pointer to Power Manager globals
; A0 - 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.
;________________________________________________________________________________________
GetBatteryTimes
MOVEA.L PMgrBase,A2 ; get pointer to Power manager globals
LoadTbl PrimInfoTblPtr,A2,A1
SWAP D0 ; get the battery number
CMP.W PrimBatteryCount(A1),D0 ; do we support this many batteries?
BHS.S @NoBattery ; -> no, return zero
JmpRoutine BatteryTimePtr,A2,A1 ; run the routine (D0.W contains battery number or system)
@NoBattery CLR.L (A0)+ ; zero out the fields
CLR.L (A0)+
CLR.L (A0)+
CLR.L (A0)+
MOVEQ #0,D0
RTS
;________________________________________________________________________________________
;
; Routine: LCDScreenChk
;
; Inputs: none
;
; Outputs: CCR - BNE if LCD screen
;
; Trashes: D0, A0, A1
;
; Function: For Color QuickDraw machines, check if a flag in the video attributes sRsrc
; says we have an LCD screen for built-in video. If the sRsrc doesn't exist,
; or the flag isn't set, we assume a CRT.
;________________________________________________________________________________________
LCDScreenChk
WITH SpBlock
Cmp.w #$3FFF,ROM85 ; If Color QuickDraw is not around,
Bne.s @NoCQD ; then just leave.
Tst.l DeviceList ; If the DeviceList is empty,
Beq.s @NoDevices ; then just leave.
Move.l MainDevice,D0 ; If there isnt a MainDevice,
Beq.s @NoDevices ; then just leave.
Move.l D0,A0 ; Get the Handle to the MainDevice.
Move.l (A0),A0 ; Make it a pointer.
Moveq #0,D0 ; Prepare D0 for unsigned .w references.
Move.w gdRefNum(A0),D0 ; If theres no driver, then
Beq.s @NoDevices ; we cant do anything here.
Not.w D0 ; Convert the refNum into…
Lsl.w #2,D0 ; …a UTable index.
Add.l UTableBase,D0 ; Get a ptr to the AuxDCEHandle.
Move.l D0,A1 ; Get it into A1.
Move.l (A1),A1 ; Get the AuxDCEHandle.
Move.l (A1),A1 ; Get the AuxDCEPtr.
Lea -spBlockSize(sp),Sp ; Put a slot parameter block on the stack.
Move.l Sp,A0 ; Point to it with A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Get the slot number.
Move.b dCtlSlotID(A1),spID(A0) ; Get the spID of the video sRsrc.
Clr.b spExtDev(A0) ; Dont ask why, just clear this guy.
_sRsrcInfo ; Get the spsPointer.
Bne.s @AssumeCRT ; If failed, just quit.
Move.b #sVidAttributes,spID(A0); Say to get the video sRsrc attributes.
_sReadWord ; Get em.
Bne.s @AssumeCRT ; If failed, just quit.
Moveq #1<<fLCDScreen,D0 ; Mask off the LCD bit in the sRsrc attributes.
And.w spResult+2(A0),D0
@Done Lea spBlockSize(sp),Sp ; Clean up the stack.
@NoDevices Rts ; Return to caller.
@AssumeCRT Moveq #0,D0 ; Set CCR appropriately.
Bra.s @Done
@NoCQD Moveq #0,D0 ; Set CCR appropriately.
Rts ; Return to caller.
;________________________________________________________________________________________ <K12>
; |
; Routine: GetDimTimeout (PowerMgrDispatch selector #29) v
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - sleep timeout (number of 15 second intervals)
;
; Trashes: A0
;
; Function: returns the current sleep timeout time
;________________________________________________________________________________________
GetDimTimeout
MOVEQ #0,D0 ; assume the result is zero
MOVE.L DimmingWaitTime(A2),D1 ; get value from globals
BEQ.S @Done
DIVU.L #pram2ticks,D1 ; convert from ticks value to 15 sec intervals
MOVE.B D1,D0 ; return result
@Done RTS
;________________________________________________________________________________________
;
; Routine: SetDimTimeout (PowerMgrDispatch selector #30)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: sleep time to set (number of 15 second intervals)
;
; Outputs: D0 - result code (always zero)
;
; Trashes: D1, A0
;
; Function: sets the current sleep timeout
;________________________________________________________________________________________
SetDimTimeout
SWAP D0 ; get the new value
MOVEQ #0,D1 ; clear reg
MOVE.B D0,D1 ; get the new value
MULU.W #pram2ticks,D1 ; set ticks value
MOVE.L D1,DimmingWaitTime(A2) ; save value in globals
_UsrIdleUpdate
MOVEQ #0,D0 ; return noErr
RTS
;________________________________________________________________________________________
;
; Routine: DimControl (PowerMgrDispatch selector #31)
;
; Inputs: A2 - pointer to Power Manager globals
; D0 - high word: 0=disable sleep, 1=enable sleep
;
; Outputs: D0 - result code (always zero)
;
; Trashes: A0
;
; Function: Disables or enables auto sleep by incrementing or decrementing the auto sleep
; semaphone. Note that since the semaphore supports multiple levels, if it's
; been disabled n times in a row, it needs to be enabled n times before auto
; sleep will really be enabled.
;________________________________________________________________________________________
DimControl
SWAP D0 ; get the flag
TST.W D0 ; enable or disable?
BEQ.S @disable ; -> disable
SUBQ.B #1,DimmingDisable(A2) ; pop a level towards sleep enabled
BGE.S @done ; -> haven't rolled over
CLR.B DimmingDisable(A2) ; pin the semaphore a zero
BRA.S @done ;
@disable ADDQ.B #1,DimmingDisable(A2) ; set the semaphore to >0 (push a level)
BHI.S @done ; -> we're done if it's still >0
SUBQ.B #1,DimmingDisable(A2) ; it rolled over, so make it >0 again
@done MOVEQ #0,D0 ;
RTS ; <K12>
;________________________________________________________________________________________
;
; Routine: IsDimmingDisabled (PowerMgrDispatch selector #32)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - boolean: 1=disabled, 0=enabled
;
; Trashes: none
;
; Function: returns a boolean telling whether dimming is enabled or disabled
;________________________________________________________________________________________
IsDimmingDisabled
MOVEQ #0,D0 ; assume enabled
TST.B DimmingDisable(A2) ; IF counting semaphor not nil THEN
BEQ.S @Done ;
MOVEQ #1,D0 ; tell the world it's disabled
@Done RTS ; that's all folks
;________________________________________________________________________________________
;
; Routine: IsAutoSlpDisabled (PowerMgrDispatch selector #33)
;
; Inputs: A2 - pointer to Power Manager globals
;
; Outputs: D0 - boolean: 1=disabled, 0=enabled
;
; Trashes: none
;
; Function: returns a boolean telling whether autosleep is enabled or disabled
;________________________________________________________________________________________
IsAutoSlpDisabled
MOVEQ #0,D0 ; assume enabled
TST.B AutoSlpDisable(A2) ; IF counting semaphor not nil THEN
BEQ.S @Done ;
MOVEQ #1,D0 ; tell the world it's disabled
@Done RTS ; that's all folks
RTS
ENDIF ; {hasPwrControls}
END