; ; Hacks to match MacOS (most recent first): ; ; 8/3/92 Elliot make this change ; 9/2/94 SuperMario ROM source dump (header preserved below) ; ; ; File: PowerMgrPatches.a ; ; Contains: patches for the power manager ; ; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 9/1/93 SKH Rolling in from Horror. These patches will get removed and rolled into PowerMgr ; when Kaos has stopped changing. ; ; <16> 5/5/92 DTY #1026866: fixed a bug where the code was testing the pointer to ; the buffer not the buffer. "pmSBuffer" is a pointer, not the ; buffer. ; <15> 4/21/92 DTY #1026866: rolled in fixes for powerbooks. bugs fixed includes ; the following ... 1) aborting sleep queue if result was non zero ; in in all sleep case (routines were shuffled around to allow ; reuse by second patch) 2) serial speed problems due to 100us ; delay when powering off the floppy 3) floppy eject problem when ; HD inserted and waking up. ; ; <14> 2/17/92 DTY Add hasTerror conditional to PowerMiscPatches InstallProc so ; that it only loads on Terror ROM machines. ; <13> 2/12/92 JSM Moved this file to PowerMgr folder, keeping all the old ; revisions; cleanup header. ; <12> 12/31/91 RB Removed some definitions that are now in Traps.a and ; PowerPrivEqu.a ; <11> 12/30/91 RB Added a few WITH's needed for this file because the PowerMgr ; interfaces changed and were moved to PowerPrivEqu.a. ; <10> 10/28/91 SAM/KSM Rolled in Regatta file: ; (HJR) Fix bug where system crashes when a new a low power dialog ; comes in after the shorted battery dialog is set. This is done ; by patching the BatInt to handle remove messages appropriately. ; (ag) don't patch sound watch on asahi. allow rom code to turn ; off sound power when not in use. ; (eva) fixed bug that was causing 976 to crash by saving out and ; restoring d7 at beginning and end of the PMgrTrapII routine. ; oops. ; (djw) Fix modem sound feedback problem by disabling playthrough ; on modem sound off routine. ; (HJR) removed default _IdleDelay time patch. Fixed bug in ; _PmgrOp delay patch. Added wake task routine to set power ; warning level back to 5.90V. Patch BatWatch VBL task to change ; power warning level to 6.09V on first occurrence 10sec warning. ; Fixed ROM problem on invalid PRAM, sleep and HD times were not ; set to defaults. Fixed bug in Portable BatWatch code using low ; mem scratch area (GetParam) instead of stack at interrupt time. ; (djw) Changed default _IdleDelay time from 15 to 6 secs. ; Patched out SerialPowerOn to power on SCC before releasing modem ; reset (as per request from Paris guys). ; (HJR) Changed the SetCursor patch to look in the right place on ; the stack for the cursor ; (djw) Rearranged Terror power manager patches to use a single ; InstallProc instead of many separate ones. Lowered the max ; number of power cycling iterations. Patch _Sleep to fix ; reentrancy problem. Install general sleep queue element for ; all system type sleep queue bug fixes. Patch _SetCursor to ; disable powercycling on watch cursor and to detect activity. ; Replace SndWatch VBL task to take DFAC activity into account ; before powering off Batman. Patch _PmgrOp to add a 100µs delay ; to avoid a race condition between 68K and pmgr micro. Add ; sleep queue task on wake to turn on Batman if DFAC enabled. ; Replace ModemSound interrupt handlers to route sound thru ; attenuator. On Portable, do a KdbReset earlier in wake routine. ; (ag) Changed low power warning level in power manager micro to ; increase wake hysteresis. ; (HJR) Added InstallProc for new sleepqueue element to save and ; restore cursor appropriately before and after sleep. ; (MSH) Changed the SCCWakeFix to not wake up the modem while ; servicing the Serial wake up IRQ. ; (ag) Installed "bad battery" strings into power manager globals. ; Changed threshold level to 5.60 volts cutoff. ; added bypass of network sleep dialog. added ashai to backlight ; test in patches. changed network warning dialog to default to ; sleep ; (ag) added ashai to backlight test in patches. (HJR) Added ; "with PMgrRec" everywhere. ; Split off from 7.0 GM sources. Added low power and SCSI Link ; warnings. ; <9> 8/30/91 DTY Define onHcMac here, since it’s not an available feature in ; BBSStartup any more. ; <8> 4/10/91 ag HJR: changed the location of the insleep semaphore. the old ; location was being overwritten by other parts of the power ; manager. moved an installproc to the head of the file in insure ; it is executed BEFORE the patchproc which uses variables it ; initializes. ; <7> 2/22/91 ag MSH: Added aruba support to the powermgr install code, new low ; power string, and patched vbls. ; <6> 2/15/91 ag MSH: #BRC 80886 - Changed sleep code and wake code to allow ; sleep queue elements to use network services. This included ; moving the close of appletalk until after the sleep queue is run ; on sleep, and opening appletalk before running the sleep queue ; on wake. the running the sleep queue on sleep, the queue is run ; in reverse order to allow service consumers to be run before ; service producers. finally, a change was added to avoid ; re-entering the sleep code (this would be very bad!!!). ; <5> 2/1/91 eh (hjr) Fixed bug that was causing serial data bytes to ; occassionally be transposed. Now all code paths call PollProc ; BEFORE re-enabling interrupts. ; <4> 12/19/90 ag As it turns out, elements of the sleep queue need interrupt on ; (the old bug kept it working!). Therefore, the wake code must be ; patched to handle restoring context and interrupts BEFORE waking ; the sleep queue. Also removed changes made in <3> since the ; change in wakeup removes the necessity of avoiding the Delay ; trap.(reviewed by MSH). ; <3> 12/14/90 ag changed delay trap calls to dbra loops. this avoids turning on ; interrupts. added patch to serial power off to allow patching ; delay call in power off trap. (reviewed by DJW) ; <2> 9/21/90 VL Removed unnecessary include files. ; <1> 9/21/90 VL Moved the PowerMgr patches from PatchPortableROM.a. All the ; patches in this file are linked patches. The whole exodus was ; prompted by the need to load the Notification Manager patches ; before anything else (including the PowerMgr patches). ; if (&type('onHcMac') = 'UNDEFINED') then onHcMac: equ 1 endif load 'StandardEqu.d' include 'LinkedPatchMacros.a' include 'HardwarePrivateEqu.a' include 'ATalkEqu.a' include 'UniversalEqu.a' include 'IOPrimitiveEqu.a' include 'PowerPrivEqu.a' AllClose ROMBind (Portable,$4946) BatIntCont ROMBind (IIci,$88660) CloseAppleTalk ROMBind (IIci,$8957E) didqueue ROMBind (IIci,$89194) DoQueue ROMBind (Portable,$4776) DreamAway ROMBind (IIci,$8911C) GetLevel ROMBind (Portable,$4176),(IIci,$887B2) InitSCSI ROMBind (Portable,$0732) InstallMsg ROMBind (Portable,$413A),(IIci,$8877A) KbdReset ROMBind (Portable,$496c) PMGRrecv ROMBind (Portable,$4014),(IIci,$885d2) PMGRsend ROMBind (Portable,$4016),(IIci,$885d4) RemoveMsg ROMBind (Portable,$4124),(IIci,$8875C) ROMCheckAppleTalk ROMBind (IIci,$89488) ROMPmgrOp ROMBind (IIci,$888ec) SlpQInstall ROMBind (IIci,$8976C) SlpQRemove ROMBind (IIci,$89784) SetSupervisorMode ROMBind (IIci,$89474) SomeSleepProc ROMBind (Portable,$4628) Burninate InstallProc (Portable) WITH PmgrRec,pmCommandRec,SleepqRec leaResident WakeQRec,A0 leaResident SCCWakeFix,A1 MOVE.L A1,SleepqProc(A0) MOVE.W #slpQType,SleepqType(A0) CLR.W SleepqFlags(A0) _SlpQInstall LEA -20(SP),SP MOVE.L SP,A0 MOVE.L #$10077,D0 ; Portable: SleepFlags _ReadXPRam MOVE.B (A0),D1 AND.B #(1< sleepDemand @doQ BSR.W DoQueueStack ; Walk the queue BNE.S AbortSleep ; Ok to goto sleep ? Nope. Get out! BSR.W CloseAppleTalk ; Else shut down atalk BCLR #InSleep,PmgrFlags(A0) ; clr the sleep indicator jmpROM SomeSleepProc AbortSleep BCLR #InSleep,PmgrFlags(A0) ; Clear the sleep indicator Exit MOVE.W D2,D0 ; Restore sleep type to D0 MOVEM.L (SP)+,A0-A6/D1-D7 MOVE.W (SP)+,SR RTS ; Return to caller ;——————————————————————————————————————————————————————————————————————— ; ; 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 ;________________________________________________________________________________________ ; ; 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 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 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 jsrROM 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 ; 1 is sleep button RTS ;——————————————————————————————————————————————————————————————————————— ; ; 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 portaSysTask PatchProc _SystemTask,(Portable) WITH PmgrRec jsrOld MOVE.L PmgrBase,A1 TST.B MBState BNE.S @clicked @idleUpdate _IdleUpdate RTS @clicked TST.B watchCrsr(A1) BNE.S @idleUpdate 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 PROC EXPORT WITH PmgrRec,pmCommandRec,SleepqRec 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 CMP.W #1,D1 BNE.S @callproc TST.W D0 BNE.S @exit ; if result != zero, exit @callproc MOVE.L d1,d0 ; restore type to d0 MOVEM.L ProcRegs,-(sp) ; save the world before calling proc <15> ag MOVE.L SleepqProc(a0),a1 ; get a pointer to the proc JSR (a1) ; call sleep proc MOVEM.L (sp)+,ProcRegs ; restore the world TST.L d0 ; set condition codes on result RTS @noelement moveq #0,d0 ; clear result @exit RTS ; exit portaPowerOff PatchProc _PowerOff,(Portable) MOVE.W #60,A0 _Delay SUB #4,SP ; clear pmData MOVE.L SP,A0 CLR.L (A0) MOVEQ #0,D1 MOVEQ #pMgrADBoff,D0 MOVE.L A0,-(SP) ; pmRBuffer -> pmData MOVE.L A0,-(SP) ; pmSBuffer -> pmData MOVE.W D1,-(SP) ; pmLength = 0 MOVE.W D0,-(SP) ; pmCommand = pMgrADBoff MOVE.L SP,A0 _PmgrOp LEA 8(SP),SP ; fix the stack, preserving A0 (why?) MOVE.L (SP)+,A0 ADD #4,SP _HideCursor CLR.L WarmStart MOVE.W #SleepNow,D0 _Sleep RTS pollProcRegs reg d0-d6/a0-a4 ;----------------------------------------------------------------------------------------- ; ; 1/29/90 MSH SCCWakeFix - Can you beleive another hardware problem with the serial <8> ; ports? This one concerns external modems connected while the SCC is turned ; off. The machine will lock up after going to sleep and waking a few times ; because the external device somehow makes the SCC generate an interrupt. ; The fix is an entry in the sleep queue that resets the SCC when no drivers ; are using it. ; ;----------------------------------------------------------------------------------------- SCCWakeFix PROC EXPORT EXPORT WakeQRec CMP.W #SleepWakeUp,D0 ; Execute only during wake up BNE.S @boogie MOVE.B PortAUse,D0 ; And only if the serial ports are free AND.B PortBUse,D0 BPL.S @boogie MOVE.B #1,D0 ; Power up a channel (no modem) <6> MSH _SerialPower MOVE.L SCCWr,A0 ; Reset the SCC MOVE.B #9,actl(A0) MOVE.B #$C0,actl(A0) MOVE.B #$81,D0 ; Power off the channel (no modem) <6> MSH _SerialPower @boogie MOVEQ #0,D0 RTS WakeQRec DC.L 0 DC.L 0 DC.L 0 ENDPROC ;_______________________________________________________________________ ; ; SndWatch - A vbl task called once every ten seconds. Checks the sound ; latch for ASC new use. If so then sound power is turned on. If power is ; already on then then the latch is cleared. Leave power on to the sound ; circuit on backlighted units, noise problems. ;_______________________________________________________________________ SndWatch PROC WITH PmgrRec MOVE.L PmgrBase,A2 LEA SwVBLTask(A2),A0 ; Get pointer to vbl task MOVE.W #SndWFreq,vblCount(A0) ; Do it again SUB.W #4,SP ; Create stack frame MOVE.L SP,A0 MOVE.W #SoundRead,D0 ; PMGR command, get sound state jsrROM PMGRrecv MOVE.B (A0),D2 ; Get sound state BTST #1,D2 BEQ.S @Clearlatch ; Branch if latch is set _IdleUpdate ; update activity indicator @Clearlatch MOVE.B #sndOnclrLtch,(A0) ; Turn on sound power and clear the latch MOVEQ #1,D1 ; One byte to send MOVE.W #SoundSet,D0 ; PMGR command, set sound state jsrROM PMGRsend @noSound ADD.W #4,SP ; Release stack frame RTS endproc ;_______________________________________________________________________ ; ; BatWatch - Battery monitoring for low power conditions. If so, ; the user is alerted via the notification manager. Dirty sleep and ; hard disk time outs are updated too. ; ; Upon entry: A1 - VIA base ; ; ; A0-A3, D0-D3 are preserved by the interrupt dispatcher. ; ;_______________________________________________________________________ BatWatch PROC WITH PmgrRec WITH SleepQRec,pmCommandRec ; <11> rb MOVE.L PmgrBase,A2 ; TST.B SysTaskFlag(A2) ; is it ok to use notification manager BNE.S @didsystask ; ... if yes, check battery LEA BatVBLTask(A2),A0 ; Get pointer to vbl task MOVE.W #BatFreq,vblCount(A0) ; Do it again RTS @didsystask jsrRom GetLevel ; 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 jsrRom 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) BNE.S @lpowermode ; <2> … continue with low power stuff MOVEQ #1,D0 ; <2> … remap level 2 to level 1 @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 jsrRom RemoveMsg ; Remove previous level message jsrRom 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 MOVE.L Rombase,A1 ; Check for version of PRAM <12> HJR CMP.W #$67C,8(A1) ; Are we running a Terror Machine <12> HJR BEQ.S @TerrorMachines ; Branch not portable or asahi. <12> HJR TST.B TOdirtyFlag(A2) ; Check for new timeouts BEQ.S @exit CLR.B TOdirtyFlag(A2) ; Clear the dirty flag SUB.W #8,SP ; allocate buffer <12> HJR MOVE.L SP,A0 ; Set buffer pointer <12> HJR MOVE.L #$080070,D0 ; Read our parameters _ReadXPRam MOVE.B 7(A0),SleepFlags(A2) ; Portable & Asahi use PRAM 77 as SleepFlags <12> to next <12> HJR MOVE.W (A0),SleepTime(A2) ; Get latest timeouts ADD.W #8,SP ; Free buffer _IdleUpdate BRA.S @exit @TerrorMachines TST.B LastLevel(A2) ; Is the level -1 BPL.S @Next ; Not try next check BCLR #PmgrWakeLvlSet,PmgrFlags(A2) ; Is the semaphor set BEQ.S @FinishUp ; Nope. Then skip and go on MOVE.B #(PMGRWARNLEVEL-STDOFFSET),D0 ; Otherwise, set warning level to 5.90 V BSR.S @SetPmgrLevl ; go do it... BRA.S @FinishUp ; and get on with life @Next CMP.B #4,LastLevel(A2) ; Check if we are in level 4 BNE.S @FinishUp ; If not, go on TST.B Level4Cnt(A2) ; Is it the first time through BNE.S @FinishUp ; If not, go On MOVE.B #(PGMRWAKELEVEL-STDOFFSET),D0 ; Set hysteresis to 6.09 BSET #PmgrWakeLvlSet,PmgrFlags(A2) ; Set the semaphor BSR.S @SetPmgrLevl ; go do it... @FinishUp TST.B TOdirtyFlag(A2) ; Check for new timeouts BEQ.S @exit CLR.B TOdirtyFlag(A2) ; Clear the dirty flag SUB.W #8,SP ; allocate some stack space MOVE.L SP,A0 ; set param block MOVE.L #$080070,D0 ; Read our parameters _ReadXPRam MOVE.B 2(A0),SleepFlags(A2) ; Terror use Pram 72 as SleepFlags HJR MOVE.W (A0),SleepTime(A2) ; Get latest timeouts ADD.W #8,SP ; free the buffer _IdleUpdate @exit RTS @SetPmgrLevl LEA -(PmBlkSize+4)(SP),SP ; Get a little storage LEA @SetLvlParm,A0 ; point to the packet MOVE.B D0,2(A0) ; set the appropriate level MOVE.L A0,pmSBuffer(SP) ; point to the packet MOVE.W #3,pmLength(SP) ; send 3 bytes MOVE.W #xPramWrite,pmCommand(SP); write to x pram MOVE.L SP,A0 ; set pointer _PmgrOp LEA (PmBlkSize+4)(SP),SP ; Release stack frame RTS @SetLvlParm DC.B ($42) ; pram byte 0x42 DC.B 1 ; one bytes of data DC.B 0 ; warn level to set on pmgr <12> from last <12> HJR ENDPROC portaInstallWake InstallProc (Portable) MOVE.L PmgrBase,A1 leaResident portaWakeUp,A2 MOVE.L A2,PmgrRec.WakeVector(A1) RTS portaWakeUp PROC EXPORT WITH PmgrRec MOVE.L #wmStConst,WarmStart MOVE.L SndBase-4,SP MOVE.W #6,RAMconfigBase MOVE.L PmgrBase,A2 CLR.B Level4Cnt(A2) MOVE.B #$FF,LastLevel(A2) CLR.L BatQ(A2) CLR.L BatQ+4(A2) MOVE.B #8,BatQIndex(A2) MOVE.L ASCBase,A0 LEA $808(A0),A0 ; unknown offset?! MOVEQ #6,D0 @ascResLoop MOVE.B (SP)+,-(A0) DBRA D0,@ascResLoop TST.B ascFifoInt(A0) MOVE.L VIA,A0 MOVEM.W (SP)+,D0-D5 MOVE.B D0,vBufB(A0) MOVE.B D1,vDIRB(A0) MOVE.B D2,vBufA(A0) MOVE.B D3,vIER(A0) MOVE.B D4,vACR(A0) MOVE.B D5,vPCR(A0) MOVE.B vT2CH(A0),vT2CH(A0) MOVE.B vT1CH(A0),vT1CH(A0) MOVE.L (SP)+,ResetPC jsrROM InitSCSI ; Init the SCSI chip LEA Time,A0 ; Restore Time MOVEQ #timeRead,D0 jsrROM PMGRrecv jsrROM KbdReset ; clear the keyboard maps MOVEM.L (SP)+,D1-D7/A0-A6 SUB #56,SP MOVE.W 56(SP),SR BSR SCSIDiskWakeAlert ; check if a disk mode cable is plugged in BSR.S MPPOpen ; Open the driver since elements in the queue might need some MPP services MOVEQ #SleepWakeUp,D0 ; Go through wake queue jsrROM DoQueue ; Run through the queue in proper order _CountADBs CMP.B #2,D0 BLE.S @noReInit _ADBReInit @noReInit MOVEQ #0,D0 MOVEM.L (SP)+,D1-D7/A0-A6 ADD.L #2,SP RTS ;——————————————————————————————————————————————————————————————————————— ; ; 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) SUB.L #ioQElSize,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 ;——————————————————————————————————————————————————————————————————————— ; ; SCSIDiskWakeAlert - Checks if the SCSI Disk Mode cable is plugged in when ; we wake up. If it is, put up a DeepShit window with a message. ; ;——————————————————————————————————————————————————————————————————————— SCSIDiskWakeAlert MOVE.L SP,D3 MOVE.L ROMBase,A0 CMP.B #$11,ROMHeader.ROMRelease(A0) BNE.W @return BSR TestForDiskMode BNE @return ; save the pixels that will be clobbered by the DS alert CLR.L D4 CLR.L D5 TST.B QDExist BNZ.S @savedErrBoxPixels MOVE.L GrafGlobals(A5),A0 MOVE.L thePort(A0),D4 MOVE.L #bitmapRec+448*126/8,D0 ; bitmap rec + 8bit data _NewPtr TST.W D0 BNE.S @savedErrBoxPixels MOVE.L A0,D5 ; this is the dest bitmap, saved... PEA bitmapRec(A0) ; set baseAddr to the guts of the buffer MOVE.L (SP)+,(A0)+ MOVE.W #56,(A0)+ ; set rowBytes MOVE.L #$00000000,(A0)+ ; topLeft MOVE.L #$007E01C0,(A0)+ ; botRight SUBA #$74,SP MOVE.L SP,A6 jsrROM AllocFakeRgns MOVE.L SP,-(SP) _InitPort MOVE.L GrafGlobals(A5),A0 MOVE.L A6,thePort(A0) PEA screenBits(A0) ; srcBits = the screen MOVE.L D5,-(SP) ; dstBits = our new allocated bitmap BCLR #7,DSAlertRect ; SECRETFLAG = 0 PEA DSAlertRect ; srcRect = rect where error box goes MOVE.L D5,A0 PEA bounds(A0) ; dstRect = our entire allocated bitmap CLR.W -(SP) ; mode = 0 CLR.L -(SP) ; maskRgn = nil _CopyBits BSET #7,DSAlertRect ; SECRETFLAG = 1 @savedErrBoxPixels ; put the alert on the screen and wait until the cable is removed... MOVE.W #dsSCSIWarn,D0 ; put up the DeepShit alert _SysError @NotGone MOVEA.L VIA,A0 MOVEQ #3,D1 @OuterLoop MOVE.W #$7FFF,D0 @InnerLoop TST.B (A0) ; throttle the loop with a VIA access DBRA D0,@InnerLoop DBRA D1,@OuterLoop BSR TestForDiskMode ; is the disk mode cable still attached? BEQ.S @NotGone ; -> yep, keep waiting ; they finally removed the cable, so clean everything up... TST.L D5 BEQ.S @useGNE MOVE.L D5,-(SP) ; srcBits = our bitmap MOVE.L GrafGlobals(A5),A0 MOVE.L A6,thePort(A0) PEA screenBits(A0) ; dstBits = the screen MOVE.L D5,A0 PEA bounds(A0) ; srcRect = our entire allocated bitmap BCLR #7,DSAlertRect ; SECRETFLAG = 0 PEA DSAlertRect ; dstRect = rect where error box goes CLR.W -(SP) ; mode = 0 CLR.L -(SP) ; maskRgn = nil _CopyBits BSET #7,DSAlertRect ; SECRETFLAG = 1 MOVE.L D5,A0 _DisposePtr ADDA #$74,SP BRA.S @reSetPort @useGNE CLR.B DSWndUpdate ; flag GNE to remove the alert TST.L D4 BEQ.S @return @reSetPort MOVE.L D4,-(SP) _SetPort @return RTS ;——————————————————————————————————————————————————————————————————————— ; ; TestForDiskMode - checks if we're setup for SCSI Disk Mode ; ; input ; none ; ; output ; CCR - BEQ if the SCSI DiskMode cable is attached ; ;——————————————————————————————————————————————————————————————————————— TestForDiskMode MOVE.L #$00EE01<<8,-(SP) ; populate pmData MOVE.L SP,-(SP) ; pmRBuffer -> pmData MOVE.L (SP),-(SP) ; pmSBuffer -> pmData MOVE.W #3,-(SP) ; pmLength MOVE.W #readPmgrRAM,-(SP) ; pmCommand MOVE.L SP,A0 _PmgrOp MOVE.L pmCommandRec.pmData(SP),D0 BTST #29,D0 LEA pmCommandRec.pmBlkSize(SP),SP RTS portaInitializeStrings InstallProc (Portable) ;___________________________________________________________________________________ ; Routine: InitializeStrings ; ; Inputs: none ; ; Outputs: none ; ; Destroys: d0-d3,a0-a2 ; ;___________________________________________________________________________________ InitializeStrings SignatureReg equ $FC0200 ; address of backlight signature SignatureAruba equ $A5 ; signature for aruba backlight SignatureUpgrd equ $A3 ; signature for upgrade backlight SignatureAsahi equ $AD ; signature for asahi backlight LPsicnNum EQU -16386 ; Small battery icon LPstr0Num EQU -16386 ; no backlight LPstr0NumBL EQU -16511 LPstr1NumBL EQU -16512 LPstr2NumBL EQU -16516 ; Added new one for Andy HJR LPstr3NumBL EQU -16513 BatstrWarn0 EQU -16514 ; new bad battery strings BatstrWarn1 EQU -16515 WITH PmgrRec MOVE.L PmgrBase,A2 MOVE.L #'SICN',D1 MOVE.W #LPsicnNum,D2 BSR GetDetachRes ; Get the battery icon BEQ.S @getstrings MOVE.L A1,lpSICNHndl(A2) ; Save the handle locally @getstrings MOVE.L #SignatureReg,A0 CMP.B #SignatureAruba,(A0) BEQ.S @dimmable CMP.B #SignatureUpgrd,(A0) BEQ.S @dimmable CMP.B #SignatureAsahi,(A0) BEQ.S @dimmable MOVEQ #3,D4 ; strings for non-backlit screen MOVE.W #LPstr0Num,D2 MOVEQ #lpSTR0Ptr,D3 @loop BSR LoadString SUB.W #1,D2 ADD.L #4,D3 DBRA D4,@loop BRA @return @dimmable move.w #LPstr0NumBL,D2 ; get first warning string move.l #lpSTR0Ptr,D3 bsr LoadString move.w #LPstr1NumBL,D2 ; get 25% warning string move.l #lpSTR2Ptr,D3 bsr LoadString move.w #LPstr3NumBL,D2 ; get 10 second warning move.l #lpSTR3Ptr,D3 bsr.s LoadString @return rts ;------------------------------------------------------------------------------------------ ; ; LoadString - used to load a low power string into the power manager globals ; ; input ; a2 - pointer to powermgr ; d2 - string resource id ; d3 - offset of string pointer in powermanager ; ; output ; none ; ; usage ; d d1 - resource type ; d2 - string resource id ; d3 - offset of string pointer in powermanager ; d a1 - handle to string ; a2 - pointer to powermgr ;------------------------------------------------------------------------------------------ LoadString move.l #'STR ',d1 ; set to string resource type bsr.s GetDetachRes ; get and detach string resource beq.s @exit ; if no string, exit move.l (a1),(a2,d3) ; else install pointer in pmgr globals @exit rts ; done ; Gets and detaches a resource. ; Parameters: ; D1 Resource Type ; D2 Resource ID ; Returns: ; A1 Handle to resource ; Registers: ; D0/A0 destroyed GetDetachRes SUBQ.L #4, SP ; For return address MOVE.L D1, -(SP) ; Resource type MOVE.W D2, -(SP) ; Resource ID _GetResource MOVE.L (SP), A1 ; Get resource handle to return _DetachResource MOVE.L A1,D0 ; Set result code RTS ;=================================================================================== thru next djw ; PowerMiscPatches - collection of all the Terror patches ; ; This routine calls all the different Terror ROM specific patches. ; ;=================================================================================== machine mc68030 InstallPowerMgrPatches InstallProc (IIci,hasTerror,hasPwrMgr) bsr ResetSoftwareCutoff ; reset the power mgr's shutdown level bsr InitializeStrings ; init all warning and alert strings bsr InstallSleepTask ; install sleep queue task to do general patches bsr PatchSetCursor ; patch _SetCursor to check for activity bsr PatchSndVBL ; install a new SndWatch VBL bsr PatchBatInt ; install a new BatInt handler HJR bsr PatchBatWatchVBL ; install a new BatWatch VBL HJR bsr PatchPmgrOp ; patch _PmgrOp rts ; from last djw ;___________________________________________________________________________________ ; Routine: ResetSoftwareCutoff ; ; Inputs: none ; ; Outputs: none ; ; Destroys: a1 ; ;___________________________________________________________________________________ ResetSoftwareCutoff WITH PmgrRec,PmgrPramRec ; <12> HJR WITH SleepQRec,pmCommandRec ; <11> rb ; set 68k cutoff voltage in pmgr globals move.l PmgrBase,A1 lea -(PmBlkSize+4)(SP),SP ; Get a little storage ; set pmgr cutoff voltage lea @PRAM_PACKET,a0 ; point to the packet move.l a0,pmSBuffer(sp) ; point to the packet move.w #4,pmLength(SP) ; <12> HJR move.w #xPramWrite,pmCommand(SP) ; write to x pram move.l SP,A0 _PmgrOp BCLR #PmgrWakeLvlSet,PmgrFlags(A1) ; Clear Hysterosis semaphor <12> to next <12> HJR move.b #(NEWCUTOFF-STDOFFSET),Cutoff(a1) ; set the new cutoff threshold to 5.75 MOVE.B #(PMGRWARNLEVEL-STDOFFSET),LowWarn(a1) ; set the new low warning threshold MOVE.L #((PmgrPramSize<<16)+\ PmgrPramBase),D0 ; Read all PMGR/Esprit data _ReadXPRam TST.B SlpTimeOut(A0) ; Check for zeroed Sleep time out BEQ.S @dowrite TST.B HDTimeOut(A0) ; Check for zeroed time outs and warning levels BNE.S @skipwrite @dowrite MOVE.B #DfltSlpTime,(A0) ; Init default time outs MOVE.B #DfltHDTime,1(A0) MOVE.L #((2<<16)+PmgrPramBase\ +SlpTimeOut),D0 ; Write _WriteXPRam ; Set them MOVE.W #((DfltSlpTime << 8) +\ DfltHDTime),SleepTime(A1) ; Writeout values to globals @skipwrite lea (PmBlkSize+4)(SP),SP ; Release stack frame move.w #$c0,PwrCycProgMax(a1) ; set max powercycle level lower <12> from last <12> HJR rts @PRAM_PACKET dc.b ($42) ; pram byte 0x42 dc.b 2 ; <8> two bytes of data dc.b (PMGRWARNLEVEL-STDOFFSET) ; <8> warn level to set on pmgr dc.b (NEWCUTOFF-STDOFFSET) ; cutoff to set tono pmgr align 4 ; djw ;___________________________________________________________________________________ ; Routine: InitializeStrings ; ; Inputs: none ; ; Outputs: none ; ; Destroys: d0-d3,a0-a2 ; ;___________________________________________________________________________________ InitializeStrings LPsicnNum EQU -16386 ; Small battery icon LPstr0NumBL EQU -16511 LPstr2NumBL EQU -16516 ; Added new one for Andy HJR LPstr3NumBL EQU -16513 BatstrWarn0 EQU -16514 ; new bad battery strings BatstrWarn1 EQU -16515 WITH PmgrRec MOVE.L PmgrBase,A2 MOVE.L #'SICN',D1 MOVE.W #LPsicnNum,D2 BSR GetDetachRes ; Get the battery icon BEQ.S @getstrings MOVE.L A1,lpSICNHndl(A2) ; Save the handle locally @getstrings move.w #LPstr0NumBL,D2 ; get first warning string move.l #lpSTR0Ptr,D3 bsr LoadString move.w #LPstr2NumBL,D2 ; get 25% warning string move.l #lpSTR2Ptr,D3 bsr.s LoadString move.w #LPstr3NumBL,D2 ; get 10 second warning move.l #lpSTR3Ptr,D3 bsr.s LoadString @batterywarn move.w #BatstrWarn0,D2 ; get 1st battery warning move.l #BBSTR0Ptr,D3 bsr.s LoadString move.w #BatstrWarn1,D2 ; get 2nd battery warning move.l #BBSTR1Ptr,D3 bsr.s LoadString rts ;------------------------------------------------------------------------------------------ ; ; LoadString - used to load a low power string into the power manager globals ; ; input ; a2 - pointer to powermgr ; d2 - string resource id ; d3 - offset of string pointer in powermanager ; ; output ; none ; ; usage ; d d1 - resource type ; d2 - string resource id ; d3 - offset of string pointer in powermanager ; d a1 - handle to string ; a2 - pointer to powermgr ;------------------------------------------------------------------------------------------ LoadString move.l #'STR ',d1 ; set to string resource type bsr.s GetDetachRes ; get and detach string resource beq.s @exit ; if no string, exit move.l (a1),(a2,d3) ; else install pointer in pmgr globals @exit rts ; done ; Gets and detaches a resource. ; Parameters: ; D1 Resource Type ; D2 Resource ID ; Returns: ; A1 Handle to resource ; Registers: ; D0/A0 destroyed GetDetachRes SUBQ.L #4, SP ; For return address MOVE.L D1, -(SP) ; Resource type MOVE.W D2, -(SP) ; Resource ID _GetResource MOVE.L (SP), A1 ; Get resource handle to return _DetachResource MOVE.L A1,D0 ; Set result code RTS ;___________________________________________________________________________________ thru next djw ; Routine: InstallSleepTask ; ; Install a new sleep queue element to handle miscellaneous system sleep patches. ; These include saving the state of the cursor before going to sleep and restore ; it after waking up. On wakeup, check the state of DFAC (sound input). If a ; source is selected, then power on Batman, otherwise do nothing (the ROM already ; powered Batman off). ; ; Also patch out the Sleep trap to fix a re-entrancy problem. ; ; Inputs: none ; Outputs: none ;___________________________________________________________________________________ InstallSleepTask MOVE.L A1,-(SP) ; Save Register LeaResident SleepPtch,A0 ; Get address of sleep code MOVE.W #$A08A,D0 ; Set the trap _SetTrapAddress ,newOS ; Install the trap MOVE.L #SleepqSize+12,D0 ; Size pf Sleep Queue element plus some extra _NewPtr ,SYS,CLEAR LeaResident SleepMiscTask,A1 ; Get pointer to Sleep Queue element MOVE.L A1,SleepqProc(A0) ; Set the Proc Pointer to our handle MOVE.W #slpQType,SleepqType(A0) ; Set the proper type _SlpQInstall ; MOVE.L (SP)+,A1 ; Restore Register RTS ;_________________________________________________________________________________________ ; PatchSetCursor - head patch setcursor ; ; Head patch setcursor to check for activity. ;_________________________________________________________________________________________ PatchSetCursor move.w #$a851,d0 ; trap number for _SetCursor _GetTrapAddress ,NewTool ; get addr of _SetCursor leaResident OldSetCursor,a1 move.l a0,(a1) ; save the old address to chain to move.w #$a851,d0 ; trap number for _SetCursor leaResident SetCursorPatch,a0 ; address of head patch _SetTrapAddress ,NewTool ; install head patch rts ;_________________________________________________________________________________________ ; PatchSndVBL - install SndWatch VBL ; ; Replace the ROM SndWatch VBL because it does not take DFAC activity into ; consideration before it clears the sound latch. This will correct a problem where ; on waking from sleep, if recording was on before sleep, it is now off. ;_________________________________________________________________________________________ PatchSndVBL movea.l PmgrBase,a2 ; get power mgr globals lea SwVBLTask(a2),a0 ; a0 = ptr to SndWatch VBL queue blk _VRemove ; remove it from the queue leaResident NewSndWatch,a1 ; a1 = addr of new SndWatch resident code move.l a1,vblAddr(a0) move.w #1,vblCount(a0) ; enable vbl element _Vinstall leaResident ModemSndOnInt,a0 ; patch out modem sound int handler move.l PmgrBase,a1 ; get pointer to globals move.l a0,MdmSndVect(a1) ; set new modem sound handler rts ;_________________________________________________________________________________________ ; PatchBatInt - install the new BatInt HJR ; ; Fix bug where system crashes when a new a low power dialog comes in after the shorted ; battery dialog is set. ;_________________________________________________________________________________________ PatchBatInt movea.l PmgrBase,a2 ; get power mgr globals leaResident NewBatInt,a1 ; a1 = ptr to NewBatInt handler move.l a1,vBatInt(a2) ; save the vector rts ;_________________________________________________________________________________________ ; PatchBatWatchVBL - install BatWatch VBL HJR ; ; Replace the ROM Batwatch VBL because it does not work. ;_________________________________________________________________________________________ PatchBatWatchVBL movea.l PmgrBase,a2 ; get power mgr globals lea BatVBLTask(a2),a0 ; get pointer to vbl queue element _VRemove ; remove it from the queue leaResident BatWatch,a1 move.l a1,vblAddr(a0) move.w #1,vblCount(a0) ; enable vbl element _Vinstall rts ;_________________________________________________________________________________________ ; PatchPmgrOp - patch _PmgrOp ; ; Install a patch to _PmgrOp to delay 100µs after a power on/off command before ; returning to the caller. This is a preventative measure to take into account that ; the pmgr micro may not have actually executed the command request when it acknowledges. ; A race condition exist where the caller may assume the power on something is on or off ; when it actually is not. ;_________________________________________________________________________________________ PatchPmgrOp move.w #$a085,d0 ; trap number for _PmgrOp leaResident PmgrOpPatches,a0 ; address of patch _SetTrapAddress ,NewOS ; install patch rts endp ; end installproc ;========================================================================================= ;========================================================================================= ; ABOVE THIS POINT IS INSTALL CODE FOR TERROR PATCHES. BELOW THIS POINT IS RESIDENT ; PATCH CODE. ;========================================================================================= ;========================================================================================= ;_________________________________________________________________________________________ ; SleepPatch ; ; This is a patch to the sleep trap so to fix a reentracy bug. ; Sleep Selector (only valid selectors) ; d0 - 1 - SleepRequest ; 2 - SleepDemand ; 6 - SleepNow ; ; input ; d0 sleep type ; d1 trapword ; ; output ; none ; ; usage ; d0 sleep type ; d1 trap word ; d2 copy of sleep type ; d3 condition code test register ; ; a0 pointer to first element/ ptr to pmgrglobals ; a1 pointer to network hook ;_________________________________________________________________________________________ SleepPtch PROC IMPORT DoQueueStack WITH PmgrRec BTST #9,D1 ; $A28A BEQ.S @TryNext ; Check if condition code is set JmpROM SlpQInstall @TryNext BTST #10,D1 ; $A48A BEQ.S @Sleep ; Check if condition code is set JmpROM SlpQRemove @Sleep ; $A08A MOVE.L PMgrBase,A0 ; Get Power Manager Base Pointer BTST #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 JsrROM SetSupervisorMode ; Set the machine to supervisor mode MOVE.W D0,PwrCycSave.PCRSRsave(A0) ; Save the store away the status register MOVE.L D1,D0 ; restore the sleep type bsr.s DreamAway ; <15> Take a snooze the new way MOVE.W PwrCycSave.PCRSRsave(A0),SR ; Restore the Status Register to the proper world @Exit RTS ;——————————————————————————————————————————————————————————————————————— <8> HJR ; <15> Sleep queue fix. DreamAway ; <15> SleepRegs REG A0-A6/D1-D7 MOVEM.L SleepRegs,-(SP) ; Save registers MOVE.L D0,D2 ; Save a sleep type in D2 @checkinprogress BSET #InSleep,PmgrFlags(A0) ; test and set sleep semaphore <17> ag BNE.S @exitsleep ; if in sleep, exit! don't re-enter @checkAuto CMP.B #SleepRequest,D0 ; auto sleep request BEQ.S @validselector @checkDemand CMP.B #SleepDemand,D0 ; User sleep, from finder or command key BEQ.S @validselector @checkNow CMP.B #SleepNow,D0 ; Critical low power sleep BNE.S @abortsleep @validselector MOVE.W PwrCycSave.PCRSRsave(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 ; Test for presence of valid hook BEQ.S @closeAT ; Nope. Branch MOVEA.L D1,A1 JSR (A1) ; Hook BNE.S @abortsleep ; IF Bad Close THEN branch BRA.S @traverse ; ELSE run the queue @closeAT jsrRom ROMCheckAppleTalk ; Close AppleTalk BNE.S @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 DoQueueStack ; Walk the queue MOVE.L D0,D1 ; Save a copy of DoQueueStack result jsrRom SetSupervisorMode ; Return to supervisor mode so that we may continue TST.L D1 ; DoQueueStack == Ok to goto sleep ? BNE.S @abortsleep ; Nope. Get out! jsrRom CloseAppleTalk ; Else shut down atalk BCLR #InSleep,PmgrFlags(A0) ; clr the sleep indicator <17> ag jmpRom didqueue ; Do the sleep shutdown @abortsleep jsrRom SetSupervisorMode ; Set the machine to supervisor mode <22> ag BCLR #InSleep,PmgrFlags(A0) ; Clear the sleep indicator <17> ag @exitsleep MOVE.W D2,D0 ; Restore sleep type to D0 MOVEM.L (SP)+,SleepRegs RTS ENDPROC ; SleepPtch ;_________________________________________________________________________________________ ; SleepMiscTask ; ; This sleep task is run for both sleep and wakeup. It executes all the miscellaneous ; system patches which can fit in a sleep queue task. ; ; Cursor state across sleep: ; Save the state of the cursor in extra space of the sleep queue element on sleep, and ; restore the state of the cursor on wakeup. ; ; Batman power state on wakeup: ; If sound input is active (i.e. there is an input source selected on DFAC), then power ; on Batman. ; ; Input: A0 = Ptr to sleep queue element ; D0 = sleep command ; ; Output: D0 - Result code. ;_________________________________________________________________________________________ Proc Export SleepMiscTask WITH PMgrRec ; <12> HJR WITH SleepQRec,pmCommandRec ; <11> rb SleepMiscTask BRA.S @HandleCommand ; Handle Sleep Queue Demand @SlpQueueDisp ; Table of offset to selector routines DC.W @SlpRequest-@SlpQueueDisp ; SleepRequest = 1 DC.W @SlpDemand-@SlpQueueDisp ; SleepDemand = 2 DC.W @SlpWakeUp-@SlpQueueDisp ; SleepWakeUp = 3 DC.W @SlpUnlock-@SlpQueueDisp ; SleepUnlock = 4 DC.W @SlpDeny-@SlpQueueDisp ; SleepDeny = 5 @LastVect DC.W @SlpNow-@SlpQueueDisp ; SleepNow = 6 @HandleCommand SUBQ.W #1,D0 ; Convert commands to zero base CMP.W #(@LastVect-@SlpQueueDisp)/2,D0; check if in range BHI.S @OutOfRange ; Nope. Out of here folks MOVE.W @SlpQueueDisp(D0.W*2),D0 ; get the offset to that routine JMP @SlpQueueDisp(D0) ; Jump to that routine @OutOfRange MOVE.W #paramErr,D0 ; Abort and return error RTS @SlpRequest BRA.S @Done ; Bye folks @SlpDemand BSR.S SaveCursor ; Time to save the cursor moveq #SleepDemand,d0 ; tell blocksonyvbl what kind of queue event<15> ag BSR BlockSonyVBL ; <15> ag BRA.S @Done @SlpWakeUp BSR.S RestoreCursor ; Restore Cursor BSR.S BatmanPower ; decide whether to power on sound BSR.S SetPwrLvlTask ; Set PowerMgr power level <12> HJR moveq #SleepWakeUp,d0 ; tell blocksonyvbl what kind of queue event<15> ag BSR BlockSonyVBL ; <15> ag BRA.S @Done @SlpUnlock @SlpDeny BRA.S @Done ; Bye folks @SlpNow BSR.S SaveCursor ; Time to save the cursor ** BRA.S @Done ; (fall thru) @Done MOVEQ #0,D0 ; Return noErr RTS ;_________________________________________________________________________________________ ; SaveCursor - misc sleep queue task ; ; This routine will save the current cursor in some extra space allocated in the ; sleep queue element. ; ; Enter: A0 - Ptr to sleep queue element ; ; Exit: none ;_________________________________________________________________________________________ SaveCursor MOVE.L A1,-(SP) ; Save register MOVE.L (A5),A1 ; point to QuickDraw globals LEA Arrow(A1),A1 ; Get pointer to current cursor MOVE.L A1,SleepqSize(A0) ; save the address of cursor in our little storage MOVE.L (SP)+,A1 ; Restore register RTS ; Goodbye ;_________________________________________________________________________________________ ; RestoreCursor - misc sleep queue task ; ; This routine will restore the state of the cursor after wake-up with the cursor stored ; in the queue element. ; ; Enter: A0 - Ptr to sleep queue element ; ; Exit: none ;_________________________________________________________________________________________ RestoreCursor MOVE.L SleepqSize(A0),-(SP) ; Get ptr to saved crsr in slpqueue element _SetCursor ; Set the cursor _ShowCursor ; Show it to the world RTS ; Goodbye ;_________________________________________________________________________________________ ; BatmanPower - misc sleep queue task ; ; The ROM on waking from sleep has powered off Batman. Because we forgot to do this ; in the ROM, we must now check the state of DFAC. If a sound input source has been ; selected, then power Batman back on so sound input will work. ; ; Input: a0 = ptr to sleep queue element ; ; Output: none ;_________________________________________________________________________________________ BatmanPower jsrTbl sndInputSource ; get current DFAC input source tst.b d0 ; anything selected? beq.s @Done ; nothing selected move.l a0,-(sp) ; save reg suba.w #4,sp movea.l sp,a0 ; a0 = ptr to data buf move.b #sndOnclrLtch,(a0) ; Turn on sound power and clear the latch moveq.l #1,d1 ; One byte to send move.w #SoundSet,d0 ; PMGR command, set sound state jsrROM PMGRsend adda.w #4,sp ; restore stack movea.l (sp)+,a0 ; restore reg @Done rts ;_________________________________________________________________________________________ <12> HJR ; SetPwrLvlTask - ; ; This routine on wakeup set the power manager power levels to appropriate wakeup ; values since it might have changed due to the 10 second level 4 count down. ; ; Input: None ; ; Output: None ;_________________________________________________________________________________________ SetPwrLvlTask MOVE.L A0,-(SP) ; Save this guy MOVE.L PMgrBase,A0 ; Get our globals BCLR #PmgrWakeLvlSet,PmgrFlags(A0) ; Clear Hysteresis semaphore LEA -(PmBlkSize+4)(SP),SP ; Get a little storage LEA @PramPak,A0 ; point to the packet MOVE.L A0,pmSBuffer(SP) ; point to the packet MOVE.W #3,pmLength(SP) MOVE.W #xPramWrite,pmCommand(SP); write to x pram MOVE.L SP,A0 _PmgrOp LEA (PmBlkSize+4)(SP),SP ; Release stack frame MOVE.L (SP)+,A0 ; Restore this guy RTS @PramPak DC.B ($42) ; pram byte 0x42 DC.B 1 ; one bytes of data DC.B (PMGRWARNLEVEL-STDOFFSET); warn level to set on pmgr @pad dc.b 0 ; pad ;________________________________________________________________________________________ ; ; Routine: BlockSonyVBL <15> ag ; ; Inputs: D0 - sleep flag ; ; Outputs: D0 - result code (always zero) ; ; Trashes: none ; ; Function: disables the Sony driver's VBL task before going to sleep, and then enables it ; after waking up so the VBL task can't run before the SWIM chip is re-initialized ;________________________________________________________________________________________ BlockSonyVBL active EQU 25 ; ≠0: .Sony driver is busy MOVE.L A1,-(SP) MOVEA.L SonyVars,A1 ; point to the Sony driver's variables SUBQ.W #SleepWakeUp,D0 ; are we going to sleep or waking up? SNE active(A1) ; $00=wakeup, $FF=sleep MOVEA.L (SP)+,A1 MOVEQ #0,D0 ; always return zero RTS ENDPROC ;_________________________________________________________________________________________ ; SetCursorPatch - check for activity ; ; Head patch SetCursor to check for activity. If SetCursor is called and the cursor ; is different from the current cursor, then we use this to indicate some level of ; program activity. Also, check specifically for the system watch cursor, and if set, ; then disable idle. If the cursor is just changing, then do an _IdleUpdate to give ; back some time. ; ; Input: 4(sp) = ptr to cursor record ; ; Output: none ; ;_________________________________________________________________________________________ Proc Export SetCursorPatch Export OldSetCursor SetCursorPatch with PowerDispRec,PmgrRec ; Check if we are updating to a different cursor from the last time move.l a2,-(sp) ; save reg movea.l PmgrBase,a2 ; a2 = ptr to power mgr globals move.l 4+4(sp),d0 ; get current addr of curRec (skipping past the saved A2) _StripAddress ; make it clean cmp.l RAMwatchPtr(a2),d0 ; are we updating the same cursor? beq.s @Done ; same one - do nothing move.l d0,RAMwatchPtr(a2) ; different - update to latest addr of curRec ; Check the new cursor mask to see if it is the watch cursor lea @WatchMask,a0 ; get mask of watch cursor movea.l d0,a1 ; a1 = ptr to cursRec adda.w #mask,a1 ; a1 = ptr to mask of new cursor moveq.l #8-1,d0 ; compare 8 longs (adjusted for dbra) @Loop cmpm.l (a0)+,(a1)+ dbne d0,@Loop ; loop until not equal tst.b d0 ; did we finish loop? bpl.s @notWatch ; not the watch cursor ; Watch cursor found - disable power cycling bset.b #0,watchCrsr(a2) ; test and set watch cursor flag bne.s @Done ; watch already detected moveq.l #IdleDisableDisp,d0 _PowerDispatch ; disable power cycling bra.s @Done ; Not the watch cursor - do an _IdleUpdate @notWatch _IdleUpdate ; give time back to system bclr.b #0,watchCrsr(a2) ; test and clr watch cursor flag beq.s @Done ; not changing from the watch cursor moveq.l #IdleEnableDisp,d0 _PowerDispatch ; enable power cycling ; Continue with the _SetCursor @Done movea.l (sp)+,a2 ; restore reg movea.l OldSetCursor(pc),a0 ; chain to old code jmp (a0) ; Watch cursor mask data @WatchMask dc.w $3f00 dc.w $3f00 dc.w $3f00 dc.w $3f00 dc.w $7f80 dc.w $ffc0 dc.w $ffc0 dc.w $ffc0 dc.w $ffc0 dc.w $ffc0 dc.w $ffc0 dc.w $7f80 dc.w $3f00 dc.w $3f00 dc.w $3f00 dc.w $3f00 align 4 OldSetCursor dc.l 0 ; location of old setcursor address ;_________________________________________________________________________________________ ; NewSndWatch - patch to SndWatch VBL task ; ; This routine replaces the SndWatch VBL task in ROM. The ROM routine does not check ; whether DFAC (sound input) is active when it decides to clear the sound latch. ; ; Input: a0 = ptr to VBL queue block ; ;_________________________________________________________________________________________ Proc Export NewSndWatch NewSndWatch move.w #SndWFreq,vblCount(a0) ; reset vbl count suba.w #4,sp ; Create stack frame movea.l sp,a0 move.w #SoundRead,d0 ; PMGR command, get sound state jsrROM PMGRrecv move.b (a0),d2 ; Get sound state beq.s @noSound ; branch if no sound activity btst.l #1,d2 bne.s @sndActive ; the latch is set jsrTBL sndInputSource ; does DFAC have a source selected? tst.b d0 bne.s @noSound ; sound input is active - do not power off sound move.b #soundoff,(a0) ; Turn off sound power moveq.l #1,d1 ; One byte to send move.w #SoundSet,d0 ; PMGR command, set sound state jsrROM PMGRsend bra.s @noSound @sndActive move.b #sndOnclrLtch,(a0) ; Turn on sound power and clear the latch moveq.l #1,d1 ; One byte to send move.w #SoundSet,d0 ; PMGR command, set sound state jsrROM PMGRsend _IdleUpdate ; update activity indicator @noSound adda.w #4,sp ; Release stack frame rts endproc ;——————————————————————————————————————————————————————————————————————— HJR to next ; ; NewBatInt - ; ; This is a bug fix where the BatInt in rom does not handle remove message ; properly. Remove message first checks whether the message to be removed ; is a low power dialog or not. Since the shorted battery dialog is not ; a low power dialog it disregards the remove. Thus, when a low dialog ; comes in, the system crashes. The fix is to aviod the check for low power ; dialog in remove message. ; ; Upon entry: A0 - Ptr to power manager data: [flags] [battery] [Gas] [Therm] ; A1 - VIA base ; A2 - Ptr to power manager globals ; ; ; A0-A3, D0-D3 are preserved by the interrupt dispatcher. ; ;——————————————————————————————————————————————————————————————————————— Proc Export NewBatInt With PmgrRec NewBatInt moveq.l #0,d2 ; clear reg move.b 1(a0),d2 ; get battery flags move.b d2,Charger(a2) ; save charger state btst.l #ShortedBat,d2 ; is there a shorted battery? beq.s @Done ; not this time ; 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. bsr.s @MyRmvMsg ; Remove any pending messages st lpMSGvalid(A2) ; Yes, then set the flag in order to remove msg JmpRom BatIntCont ; Go back into the rom code @Done rts ; @MyRmvMsg 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 endproc ; NewBatInt HJR ;_________________________________________________________________________________________ ; PmgrOpPatches - _PmgrOp patch ; ; This patch is around _PmgrOp. It notes the command to _PmgrOp, and if it is "set ; power control", then call _PmgrOp but delay returning to the caller for 100µs to ; give the power manager time to actually execute the command. This avoids a race ; condition of code trying to access some hardware before it is actually turned on. ; ; Input: a0 = ptr to pmgr command pkt ; d1 = trap word ; Output: none ;_________________________________________________________________________________________ Proc Export PmgrOpPatches WITH PMgrRec ; <12> HJR WITH SleepQRec,pmCommandRec ; <11> rb PmgrOpPatches ; Head patch to PmgrOp to add a 100µs delay after power control commands cmp.w #powerCntl,pmCommand(a0) ; power control command ? bne.s @NewPmgrOp ; no - jmp to power mgr @powerCommand ; <15> movea.l pmSBuffer(a0),a1 ; load pointer to buffer in a1 <16> btst.b #7,(a1) ; test the power on bit <16> beq.s @NewPmgrOp ; if off command, skip delay <15> jsr @NewPmgrOp ; jsr _PmgrOp move.w TimeDBRA,d1 ; <12> HJR divu #10,d1 ; divide down to 100µs <12> HJR @Loop dbra d1,@Loop ; delay 100µs tst.w d0 ; set condition codes rts ; we are done ; Patch to PmgrOp to patch SerPowerOn @NewPmgrOp and.w #$0600,d1 ; extract bits 9 and 10 from trap word cmp.w #$0600,d1 ; is it $a685 - SerialPower? beq.s @NewSerialPower jmpROM ROMPmgrOp ; execute PmgrOp in ROM ; New SerialPower patch. On SerPowerOn, assert DTR before modem reset. ; The code is the same as ROM except for DTR and reset ordering. @NewSerialPower btst.l #SerialOff,d0 ; power on or off beq.s @SerPowerOn ; do new serial power on jmpROM ROMPmgrOp ; start from beginning in ROM ;——————————————————————————————————————————————————————————————————————— ; SerPowerOn - determine power on for serial port ; ; 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 ; ; Input : d0 = bit 0: 0 = use internal modem, 1 = ignore internal modem ; bit 2: 0 = port B, 1 = port A ; @SerPowerOn @savedregs reg d0-d1/a0-a1 movem.l @savedregs,-(sp) suba.w #pmBlkSize,sp ; alloc pmgr command pkt lea pmData(sp),a0 ; get addr of buffer move.l a0,pmRBuffer(sp) ; set ptr to rcv buffer move.l a0,pmSBuffer(sp) ; set same ptr to xmit buffer (it's expected or error) movea.l sp,a0 ; a0 = ptr to pmgr command pkt ; Check whether we should bypass the modem check bclr.l #BypassModem,d0 ; set = ignore modem bne @externalPort ; use the external ports ; Determine which port we are powering on - if port A then check for modem. ; The modem may only be connected to port A. tst.b d0 ; d0 = port indicator beq @externalPort ; 1 = port A, 0 = port B ; On port A - read the modem status. If the modem is not installed power the ; external port. move.w #modemRead,pmCommand(a0); read the modem's status clr.w pmLength(a0) ; clear the count field _PmgrOp ; get the modem status move.b pmData(a0),d1 ; d1 = modem status bits btst.l #ModemInstalled,d1 ; check the modem installed bit beq @externalPort ; modem not installed - use the port ; Modem is installed - read extended PRAM to see if modem should be powered on move.l #((1<<16)+PmgrPramBase\ +PmgrPramRec.PmgrStatusFlags),d0; read Power Manager Flag byte _ReadXPRAM ; a0 = ptr to buf (writing over cmd word in pkt) btst.b #UseIntrnlModem,(a0) ; check cdev bit for modem bne @externalPort ; set - don't power modem ; Power on the modem bclr.b #7,([VIA2],vDIRB) ; set MODEM_RESET by making it an input and.b #7,d1 ; mask only bset.l #ModemPwr,d1 ; set bit in saved modem status bits move.b d1,pmData(a0) ; turn on +5V and -5V to modem bit move.w #1,pmLength(a0) ; xmit one byte move.w #modemSet,pmCommand(a0) ; modem set command _PmgrOp ; turn on +5V and -5V to modem move.w TimeDBRA,d0 asl.w #1,d0 ; calc 2ms delay @Delay dbra d0,@Delay ; wait for +5v and -5V to ramp move.b #(sccOn),pmData(a0) ; set bits to power on SCC move.w #1,pmLength(a0) ; xmit one byte move.w #powerCntl,pmCommand(a0); power control command _PmgrOp ; call the power manager move.b #(ModemOn),pmData(a0) ; enable modem - sense of bit is reversed move.w #1,pmLength(a0) ; xmit one byte move.w #powerCntl,pmCommand(a0); power control command _PmgrOp ; call the power manager move.w TimeDBRA,d0 asl.w #3,d0 ; calc 8ms delay @Delay2 dbra d0,@Delay2 ; wait for reset time move.l PmgrBase,a1 ; get pointer to globals move.l MdmSndVect(a1),jModemSnd; install in Level 1 VIA1 dispatch table move.b #((1< from last djw ;——————————————————————————————————————————————————————————————————————————————————————— ; Modem Sound Interrupt Handlers ; ; Modem sound in ROM is implemented through DFAC's aux channel. The aux channel is ; routed through the by-pass path which does not allow any volume control. People ; complained, so this patch routes modem sound through the attenuator which allows ; volume control. The problem is this path is shared with sound input. This patch ; does not implement any priority to the users of the patch. The last person to ; set the input source gets it. ; ; 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 ; Proc Export ModemSndOnInt ModemSndOnInt move.b #(1< djw jsrTBL sndPlayThruVol ; djw 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 endp ; from last djw End