sys7.1-doc-wip/QuickDraw/CheckDevicesINIT.a

1484 lines
60 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.

;
; Hacks to match MacOS (most recent first):
;
; <Sys7.1> 8/3/92 Elliot make this change
; 9/2/94 SuperMario ROM source dump (header preserved below)
;
;
; File: CheckDevicesINIT.a
;
; Contains: 7 patches for Color QuickDraw (mostly video driver related)
;
; Written by: Dave Fung/Mike Puckett
;
; Copyright: © 1989-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM10> 09-23-93 jmp Quit doing <SM8> below when the Display Manager is around.
; <SM8> 04-07-93 jmp Cleaned up the invalid 'scrn' resource code so that it actually
; removes the invalid 'scrn' resource. This makes family modes
; work better. However, this is really only a stop-gap measure
; for now.
; <SM7> 11-05-92 jmp Changed the TPD, FPD, and HR video driver patch mechanism so
; that it now runs correctly from ROM (it was originally written
; to work in RAM).
; <SM5> 10/28/92 PN # 1045532 Call QDSecondaryInit from the BootCode3.a to set up
; the color and gdevice environment also fix up the code to run
; from ROM and check for SuperMario ROM ID. Mike Puckett will come
; back to this file and clean it up (he promised !) Also, take out
; the system INIT stuff and the 950 patch.
; <SM3> 7/16/92 CSS Update from Reality:
; <27> 7/13/92 DTY #1035553 <csd>: The Quadra950VideoPatch assumes that the driver
; is RAM based, thus it treats the dCtlDriver field as a handle.
; Under A/UX, the video driver is a ROM based driver, and is a
; pointer. Add a check to see whether the driver is RAM based or
; ROM based before doing an extra dereference.
; <26> 05-20-92 jmp Moved the “PatchQuadra950Driver” code from VideoPatch.a to this
; file so that the patch would work both when the Quadra 950
; built-in video is the main device and when it is secondary.
; <2> 2/13/92 PN Add forRom conditionals.
; <1> • Pre-SuperMario comments follow •
; <25> 8/23/91 JSM Remove benign redefinition of TRUE, which is now defined by the
; build script.
; <24> 3/7/91 DC dba, #83785: attach the VBL to the main screen after moving
; cursor there
; <23> 11/7/90 jmp Fixed a bug that I introduced iton SixPack where 'gama' tables
; pointed to by the 'scrn' resource were not being loaded.
; <22> 7/11/90 gbm define true (this was the only file that used it when it was in
; StandardEqu.d)
; <21> 7/10/90 jmp Added another item to the “To Do” list below. NO CODE CHANGES
; WERE MADE.
; <20> 7/10/90 DDG NEEDED FOR SIXPACK: Fixed bug in setting gamma entries
; (SetDevGamma) where the csParam was being setup as if it was a
; word instead of what it really is: a long. Also fixed duplicate
; comment for change 19.
; <19> 7/4/90 jmp Cleaned up and corrected MY previous inequities (and its about
; time, too). ••• NEEDED FOR SIXPACK •••
; <18> 7/2/90 jmp Move of the same -- rolling out my changes to fix the build.
; <17> 7/2/90 jmp Put things back to the way they were because I was breaking
; everybody (Ill hang my head in shame).
; <16> 7/2/90 jmp Took out <15> changes due to breaking build -- will put back in
; later.
; <15> 7/2/90 jmp Moved the NoScrn routine to CheckDeviceINIT.c in preparation for
; $067C machine fix.
; <14> 6/29/90 jmp Various small fixes, plus added some (badly needed) comments.
; <13> 6/28/90 DTY Removed extra dereference on A2 when no 'scrn' resource is
; around, which caused Bus Error on startup. (Oops… I [jmp] left some
; bad parts of an attempted optimization in.)
; <12> 6/27/90 jmp Fixed a problem where systems that do not have a 'scrn' resource
; start out dark and then become light on the first SetGamma
; and/or SetEntries call. ••• NEEDED FOR SIXPACK •••
; <11> 5/1/90 DDG Changed a comment that indicated some permanent code was
; temporary. (no code change)
; <10> 4/24/90 dba make the cursor be on the main device, not the boot device
; <9> 4/19/90 csd corrected a typa for Darin who is completely without blame in
; this matter
; <8> 4/19/90 dba change so this can be used by StartSystemPatches.a in 7.0
; <7> 4/10/90 DF <FOR 7.0 BUILD> Fix the interrupt handler patching code here to
; correct illegal memory access when the driver is in ROM on
; Erickson
; <6> 3/2/90 DDG Early in the boot process an _InitGraf was performed (for the
; Welcome to Mac box). It's not correct if the main screen moved
; away from the boot screen, so let's call InitGraf on these early
; globals to correct the problem. This will fix a problem with the
; LMgr "init" which didn't do an InitGraf while setting up the
; environment for an alert dialog. (this comment stolen from Brian
; McGhie)
; <5> 2/5/90 DAF The INIT resource executing code at boot time requires that the
; INIT resources not trash registers (particularily D6). This fix
; crudely saves and restores all register across calls. It's
; crude because this file is really about 3 independent inits
; strung together
; <4> 2/3/90 DAF Added additional init functionality to file. This code
; fixes a bug in the interrupt-level manipulation code in
; several Apple drivers.
; <3> 1/31/90 DAF Added an AllocCursor before the ShowCursor at the end of the
; init to make sure all data structures are properly setup
; <2> 1/30/90 DAF Added secondary function which sets a GDFlag bit to identify
; 32-bit addressed frame buffers.
; <1.0> 9/21/89 DAF FOR 6.0.4 Build - Color QuickDraw CheckDevices System Init
; <1.1> 8/17/89 DAF Commented a test out (;!!!) to force the gamma and gray state to
; be flushed out to the CLUT hardware with a SetEntries.
;
; To Do:
; To eliminate flashing, it would be nice to keep some sort of tally about which
; gDevices have already had SetEntries/SetGamma calls made to them. The cases
; where this would occur are rare, but it should be looked into.
;
; This code contains lots of jumping around, and it would be nice to eliminate it.
;
; In the ••• 3rd INIT ••• there a several “Move.l DeviceList,Ax”. It might be
; nice to use something like A5 (since its free and all the registers are
; being saved) to just cache the DeviceList.
;
; If the above is implemented, the SetDevEntries and SetDevGamma utilites could
; be tightened up to some degree (i.e, saving of input register(s)).
;
; SetDevEntries and SetDevGamma should return _Control errors. (This would be handy
; in the 4th INIT when SetDevGamma fails -- e.g., the card doesnt support it -- so
; that the subsequent SetDevEntries call is NOT made.)
;
; This system file INIT basically contains the CheckDevices routine from within Color QuickDraw
; (this excerpt from gdevice.a). This INIT runs only on CQD machines.
;
; This routine normally performs validations on the 'scrn' resource and sets up the color
; and gDevice environment. It fixes two bugs. The first is related to gamma tables
; specified by ID in the 'scrn' resource. Previously, if a gamma table was specified, but a
; color table ID was NOT specified, the gamma setting would not take place until the next
; change of the device's color table. The second is an improvement of the 'scrn' validation code.
; If a mode (screen depth) is recorded in the 'scrn' resource, but that mode becomes unavailable
; (through removal of frame buffer memory), then an invalid mode may be selected. This INIT
; corrects that problem by validating the mode field.
;
; Since this routine is fairly large, and only executes once, I'm executing this code as a System
; INIT before the first _InitGraf. The code in ROM will see that the allInit flag is set, and will
; just skip over the faulty code in ROM. There's no attempt to modify the ROM version.
;
; Ive left this code as close to CheckDevices as possible. Live code that has been left out of
; this init version is marked with ';+++'.
;
; UPDATE FOR 6.0.5: I've added another INIT function to the tail end of the main Init. This
; code tests each frame buffer in the system, and sets a bit in GDFlags of it's gDevice if
; the frame buffer is to be addressed in 32-bit addressing mode. Addressing mode is independent
; of pixelsize. Only 32-bit QD equipped machines can use these frame buffers, but the
; design of the video card architecture protects non-QD 32 machines.
;
; UPDATE FOR SixPack: I (jmp) have essentially added three more INIT functions. Two of these end
; up jumping to the same piece of code, and the third (although it uses some of the code from
; the first two) is totally different. The addeded functionality in the first two INIT functions
; is to correct the problem where there is no and/or no valid 'scrn' resource in the System. To do
; this we just call SetEntries on the boot devices pmTable. The other problem is a little more
; subtle and only happens on $067C machines. The problem is that InitDefGamma (in StartInit)
; doesnt set up non-TFB, non-gamma dir cards at all. So, the INIT here is does a SetEntries
; and SetGamma on $067C machines on all non-TFB cards that contain no gamma directories.
;
MACHINE MC68020
LOAD 'StandardEqu.d'
INCLUDE 'Slots.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'Video.a'
INCLUDE 'GestaltEqu.a'
;----------------------------------------------------------------------------------------------------
; This code is only an INIT under older systems that use the old boot sequence
; for 7.0 systems it is called by StartSystemPatches instead.
if &type('asINIT')='UNDEFINED' then
asINIT: equ 0
endif
;----------------------------------------------------------------------------------------------------
if asINIT then
ThreeVideoThings MAIN
else
DavesRandomVideoStuff PROC EXPORT
endif
WITH VDPageInfo
;----------------------------------------------------------
;
; PROCEDURE CheckDevices;
;
; Look at the device list to see if it needs to be initialized. If so, read
; in the resource of type 'scrn'. If it is found, configure the devices as
; described in that resource. The format of the 'scrn' resource is:
;
; [count] ; [word] number of devices in resource
; FOR I := 1 TO COUNT DO
; [sResource Type] ; [word] spDrvrH of device n
; [slot] ; [word] slot number of device n
; [dCtlDevBase] ; [long] the dCtlDevBase of device n
; [mode] ; [word] the sRsrcID for the desired mode
; [flagMask] ; [word] masks off all bits used in flags
; [flags] ; [word] indicates the state of the device
; ; bit 0 = 0 if monochrome; 1 if color
; ; bit 11 = 1 if this device is main screen
; ; bit 15 = 1 if the screen is active
; [colorTable] ; [word] resource id of desired color table (-1=none)
; [gammaTable] ; [word] resource id of gamma table (-1=none)
; [global Rect] ; [rect] global rectangle for this device
; [CtlCount] ; [word] number of control calls following
; FOR J := 1 TO CtlCount DO
; [csCode] ; [word] control code for this call
; [length] ; [word] number of bytes in the param blk
; [param blk] ; [length] data to be passed in control call
; END;
; END;
;
; CheckDevices is called by InitGraf.
;PARAMSIZE EQU 0 ; <19> What is this for? Doesnt appear to be used.
IOPBlk EQU -IOVQElSize ; [64] parameter blk for I/O calls
SlotParms EQU IOPBlk-spBlock.SPBlockSize ; parameter block for slot manager calls
VidParms EQU SlotParms-12 ; [12] size of mode params
StartList EQU VidParms-4 ; [long] pointer to start of resource
VARSIZE EQU StartList ; size of local vars for CheckDevices
UTILVARS EQU VidParms ; size of local vars for utility routines
; ••• Start of Code •••
;
if asINIT then
CMP.W #$3FFF,ROM85 ; is this a MacII-class machine?
BEQ CheckDevices ; yup, so continue
RTS ; if not, then exit
else
Bra CheckDevices ; <19>: Jump abound utility routines. Should we make a
; real INIT out of this (i.e., using a “standard header”)?
endif
; Utilities ------------------------------------------------------------------------------------------------
;
; SetDevEntries: This routine expects A0 to contain the Handle to the gDevice (GDHandle) being set.
; If A1 contains a -1, SetDevEntries will use the pmTable, otherwise it treats A1
; as a Handle to a colorTable.
;
; If the gDevice is a directType/fixedType, SetEntries will not be called.
;
; A0 and A1 will NOT necessarily be preseverd on exit.
;
SetDevEntries
Link A6,#UTILVARS ; Allocate room for local vars.
Move.l A2,-(Sp) ; Storage for remembering gDevice.
Move.l (A0),A2 ; gDevice Handle to gDevice Ptr.
Cmp.w #directType,gdType(A2) ; If the gDevice is direct or fixed
Beq.s @sdeExit ; then do nothing.
Cmp.l #-1,A1 ; If A1 == -1, then use the
Beq.s @usePMap ; gDevices PixMap.
Move.l A1,A0 ; Otherwise copy the colorTable Handle
Bra.s @continue ; and continue on.
@usePMap Move.l gdPMap(A2),A0 ; Get the gDevices pixMaps
Move.l (A0),A0 ; colorTable.
Move.l pmTable(A0),A0 ;
@continue _HLock ; Lock down the colorTable.
Move.l A0,-(Sp) ; And save it for _HUnlock.
Move.l (A0),A0 ; Turn it into a Ptr.
Lea VidParms(A6),A1 ; Set up for SetEntries:
Clr.w csStart(A1) ; csStart = 0
Move.w ctSize(A0),csCount(A1) ; csCount = pmTable.ctSize
Lea ctTable(A0),A0 ;
Move.l A0,csTable(A1) ; csTable = &pmTable.ctTable[0]
Lea IOPBlk(A6),A0 ; Set up for Control call:
Move.w gdRefNum(A2),ioRefNum(A0) ; ioRefNum = gDevice.gdRefNum
Move.w #cscSetEntries,csCode(A0) ; csCode = cscSetEntries
Move.l A1,csParam(A0) ; csParam = &VidParams
_Control ,Immed ; Call SetEntries.
Move.l (Sp)+,A0 ; Unlock color table Handle.
_HUnlock
@sdeExit Move.l (Sp)+,A2 ; Restore A2.
Unlk A6
Rts
; SetDevGamma: This routine expects A0 to contain the Handle to the gDevice (GDHandle) being set, and
; A1 to contain a Ptr to a gammaTable.
;
; A0 and A1 will NOT necessarily be preserved on exit.
;
SetDevGamma
Link A6,#UTILVARS ; Allocate room for local vars.
Movem.l A2-A3, -(Sp) ; Storage for gDevice/gammaTable.
Move.l (A0),A2 ; gDevice Handle to gDevice Ptr.
Move.l A1,A3 ; save gammaTable Ptr.
Lea VidParms(A6),A1 ; Set up for SetGamma call:
Move.l A3,csGTable(A1) ; csGTable = gammaTable Ptr
Lea IOPBlk(A6),A0 ; Set up for Control call:
Move.w gdRefNum(A2),ioRefNum(A0) ; ioRefNum = gDevice.gdRefNum
Move.w #cscSetGamma,csCode(A0) ; csCode = cscSetGamma
Move.l A1,csParam(A0) ; csParam = &VidParams <20> Changed Move.w to Move.l (oops).
_Control ,Immed ; Call SetGamma.
Movem.l (Sp)+,A2-A3 ; Restore A2-A3.
Unlk A6
Rts
;
; ----------------------------------------------------------------------------------------------------------
CheckDevices ; <19>: Moved label from within if-endif to embed utility
; routines. It would be nice to be able to the the LINK
; stuff AFTER the GotScrn entrypoint.
LINK A6,#VARSIZE ; allocate local stack frame
MOVEM.L A0-A6/D0-D7,-(SP) ; so we dont screw up the boot process
;+++ MOVEM.L D6-D7/A2-A4,-(SP) ; save work registers
;+++; check to see if the device list needs to be initialized
;+++
;+++ MOVE.L DeviceList,A0 ; get handle to device list
;+++ MOVE.L (A0),A0 ; point to head of device list
;+++ MOVE GDFlags(A0),D0 ; get the flags word
;+++ BTST #allInit,D0 ; test initialize flag?
;+++ BNE GoHome ; => devices already initialized
; ••• 1st INIT •••
;
; Try to load in the resource. If none, then just do a SetEntries on the boot device (see
; the comments on the NoScrn code below).
;
GetScrn
TST.B scrnInval
BEQ.S NoScrn
CLR.L -(SP) ; make room for function result
MOVE.L #'scrn',-(SP) ; push desired resource type
CLR -(SP) ; resource ID = 0
_GetResource ; get the resource
MOVE.L (SP)+,D0 ; get the resource handle
BNE.S GotScrn ; if nil, do the no 'scrn' code
; If a 'scrn' resource is NOT around well get here. The only thing we want to do at this
; point is to call SetDevEntries on the boot device so that the screen will not change colors
; after a SetEntries/SetGamma call is made later.
;
NoScrn
Move.l DeviceList,A0 ; A0 contains gDevice.
Move.l #-1,A1 ; Use gDevices PixMap for colorTable.
Bsr.s SetDevEntries ;
Bra NoGammaFix
; ••• 3rd INIT •••
;
; Lock down the 'scrn' handle, and point at the data (in A4).
;
GotScrn
MOVE.L DeviceList,A0 ; get handle to device list
MOVE.L (A0),A0 ; point to head of device list
BSET #allInit,GDFlags(A0) ; say list has been initialized
MOVE.L D0,-(SP) ; save 'scrn' resource for ReleaseResource
MOVE.L D0,A0 ; get the resource
_HLock ; lock it down
MOVE.L (A0),A4 ; A4 = resource pointer
; Validate the 'scrn' resource. There must be a descriptor for every screen device.
; I assume that there are no duplicate entries and that screens don't overlap.
; In addition the devices in the 'scrn' resource must be in slot order.
;
MOVE.L A4,StartList(A6) ; save pointer to start of list
MOVE (A4)+,D7 ; get the number of screens in resource
WITH spBlock,vpBlock
LEA SlotParms(A6),A0 ; get pointer to parameter block
MOVE.L #((CatDisplay << 16) ++ TypVideo),spCategory(A0)
; set category ID, type
MOVE.W #drSwApple,spDrvrSw(A0) ; set software, hardware ID
MOVE.B #$01,spTBMask(A0) ; ignore spDrvrHw
MOVE.B #0,spSlot(A0) ; start with desired slot (0 to check built-in devices)
MOVE.B #0,spID(A0) ; start with first (zeroth) ID
CLR.B spExtDev(A0) ;
NxtDev _sNextTypesRsrc ; get next video device
BEQ.S GotDev ; => there is one
; There are no more screens; are there any more entries in the 'scrn' resource?
;
TST D7 ; there should have been one per device
BEQ GoodRsrc ; => there was, go initialize them
BRA BadScrn ;
; Scan through 'scrn' resource entry for this device.
;
GotDev MOVE (A4)+,D0 ; get type
CMP spDrvrHw(A0),D0 ; does it match?
BNE BadScrn ; => nope, bad screen resource
MOVE (A4)+,D0 ; get slot
CMP.B spSlot(A0),D0 ; does it match?
BNE.S BadScrn ; => nope, bad screen resource
; Get the DCE entry for the device and check dCtlDevBase.
; If no match, look for other devices in the same slot.
;
SlotOK MOVE spRefNum(A0),D0 ; get the refNum
NOT D0 ; refNum to unitnum
ASL #2,D0 ; offset in unitTable
MOVE.L UTableBase,A1 ; get the base of the unit table
MOVE.L (A1,D0),A3 ; A3 = handle to the DCE
MOVE.L (A3),A1 ; get pointer to the DCE
MOVE.L dCtlDevBase(A1),D0 ; get dCtlDevBase
CMP.L (A4)+,D0 ; do they match?
BNE.S BadScrn ; => nope, bad screen resource
; Test to make sure that the requested mode (screen depth) is valid in this video
; sRsrc list.
;
MOVE.B spID(A0),D1 ; save the spID (so that its correct for the sNextTypesRsrc)
MOVE.W (A4)+,D0 ; get the mode
MOVE.B D0,spID(A0) ; insert into spBlock
_sFindStruct ; find the sRsrc list entry for this mode
BNE.S BadScrn ; if not, then the scrn resource is no good
MOVE.B D1,spID(A0) ; restore the spID
; To be completely compulsive about it, make sure there's a gDevice.
;
MOVE.L DeviceList,A3 ; A3 = first gDevice in list
MOVE spRefNum(A0),D1 ; get refnum (unaffected by sFindStruct)
@NxtGD MOVE.L (A3),A1 ; get pointer to device
CMP gdRefNum(A1),D1 ; does refnum match?
BEQ.S RectCheck ; => yes, this device matches!
MOVE.L gdNextGD(A1),D0 ; get handle of next device
MOVE.L D0,A3 ; get in A3
BNE.S @NxtGD ; => check all gDevices
BRA.S BadScrn ; => no such gDevice, bad 'scrn'
; Compare the size of the remembered screenRect to the size of this gDevice's
; gdRect. At this point, the gdRects are still topleft={0,0} from InitGDevice
; so we can just check 'scrn' rect against botRight.
;
RectCheck
ADD #8,A4 ; skip to global rect in 'scrn'
MOVE.W bottom(A4),D0 ; get bottom
SUB.W top(A4),D0 ; = height
CMP.W gdRect+bottom(A1),D0 ; is it equal?
BNE.S BadScrn ; nope, we're out
MOVE.W right(A4),D0 ; get right
SUB.W left(A4),D0 ; = width
CMP.W gdRect+right(A1),D0 ; is it equal?
BNE.S BadScrn ; nope, we're out
; This device matches! Go check the next one.
;
SkipData ADD #8,A4 ; skip to control field
MOVE (A4)+,D0 ; get number of control calls
BRA.S SkipCtl ; skip control call
SkipNxt MOVE.L (A4)+,D1 ; get control code, size of params
ADD D1,A4 ; add size of params to skip block
SkipCtl DBRA D0,SkipNxt ; => skip next control
SUBQ #1,D7 ; decrement device count
BMI.S BadScrn ; => oops, bad screen resource
LEA SlotParms(A6),A0 ; get pointer to parameter block <14>
BRA.s NxtDev ; => check next device <19>: .s
; If the 'scrn' resource is bad, then let's walk down the device list and offset
; the invalid screens' gdRects so that they don't all pile up at (0,0). Let's keep
; it simple--just put them all edge-to-edge, with the top edge at 0 (unchanged) and
; to the right of the previous guys'. Offset the gdPMap's rect also.
;
BadScrn
MOVE.L DeviceList,A0 ; get the head of the list (the boot screen)
MOVE.L (A0),A0 ; hndl->ptr
MOVE.W gdRect+right(A0),D1 ; get the boot screen's right edge (if the scrn
; is invalid, then this is the real right edge)
@Loop MOVE.L gdNextGD(A0),D0 ; get handle to next screen
BEQ ScrnDone ; when NIL we're out of here <19>: Done -> ScrnDone
MOVE.L D0,A0 ; get this device
MOVE.L (A0),A0 ; handle to ptr
ADD.W D1,gdRect+left(A0) ; offset the left edge (normally zero)
ADD.W D1,gdRect+right(A0) ; offset the right edge
MOVE.L gdPMap(A0),A1 ; get the gdPMap handle
MOVE.L (A1),A1 ; get the gdPMap pointer
ADD.W D1,pmBounds+left(A1) ; offset the left edge (normally zero)
ADD.W D1,pmBounds+right(A1) ; offset the right edge
MOVE.W gdRect+right(A0),D1 ; get the new right edge for the next device
BRA.S @Loop ; for each screen
GoodRsrc _HideCursor ; cursor must be hidden here
MOVE.B #true,CrsrBusy ; MARK CHANGE IN PROGRESS
; Configure each entry in the scrn resource
;
MOVE.L StartList(A6),A4 ; save pointer to start of list
MOVE (A4)+,D7 ; get the number of screens in resource
SUBQ #1,D7 ; make it 0 based
; It would be nice if this routine could use sRsrcInfo or sNextsRsrc here, but we
; don't keep the video sRsrc spID in the scrn resource, just the hw ID!!! To
; make up for this, we must do a search by type.
;
DoNxt LEA SlotParms(A6),A0 ; get pointer to parameter block
MOVE.L #((CatDisplay << 16) ++ TypVideo),spCategory(A0)
; set category ID, type
MOVE.W #drSwApple,spDrvrSw(A0) ;
; set software, (invalid) hardware ID
MOVE (A4)+,spDrvrHw(A0) ; set driver hardware ID
MOVE.B #$00,spTBMask(A0) ; all fields valid
MOVE (A4)+,D0 ; get slot
MOVE.B D0,spSlot(A0) ; does it match?
MOVE.B #0,spID(A0) ; start with first ID
CLR.B spExtDev(A0) ;
_sNextTypesRsrc ; get next video device
;+++ BNE BadScrn ; => this should never be taken (so lets comment it out) <12>
; We found a device that matches the given description! Find its gDevice and configure it.
;
MOVE spRefNum(A0),D1 ; D1 = refnum
MOVE.L DeviceList,A3 ; A3 = first gDevice in list
@NxtGD MOVE.L (A3),A0 ; get pointer to device
CMP gdRefNum(A0),D1 ; does refnum match?
BEQ.S @GotGD ; => yes, got the gDevice
MOVE.L gdNextGD(A0),D0 ; get handle of next device
MOVE.L D0,A3 ; get in A3
BNE.S @NxtGD ; => check all gDevices
;+++ BRA BadScrn ; => this should never be taken (so lets comment it out) <12>
@GotGD MOVE.L (A4)+,D0 ; discard dCtlDevBase
; Set up the GDFlags word before calling InitGDevice.
;
MOVE.L (A3),A1 ; point at the grafDevice
MOVE gdFlags(A1),D0 ; get the flags word
AND 2(A4),D0 ; turn off the bits that are used
OR 4(A4),D0 ; turn on new bits
BSET #ramInit,D0 ; say we've initialized it
BSET #screenDevice,D0 ; and flag it as a screen device
MOVE D0,GDFlags(A1) ; set the flags word
; If main device, set up low-memory handles. (Wait: If the ramInit and screenDevice
; flags are NOT setup, then why would the mainScreen flag be setup? -- jmp)
;
MOVE gdFlags(A1),D0 ; get the flags word
BTST #mainScreen,D0 ; is it the main scrn?
BEQ.S @InitGD ; => no, go init device
MOVE.L A3,MainDevice ; set up as main screen device
MOVE.L A3,TheGDevice ; set up as default destination device
MOVE.L A3,SrcDevice ; set up as default source device
; AllocCursor called by InitCursor to init cursor
MOVE.L (A3),A0 ; point to gDevice
MOVE.L gdPMap(A0),A0 ; get pixMap handle
MOVE.L (A0),A0 ; point to pixMap
MOVE.L baseAddr(A0),D0 ; get base address
MOVE.L D0,scrnBase ; and set up screen base
LEA SlotParms(A6),A0 ; point at slot manager block again (it's still positioned from above)
MOVE (A4),D0 ; get the requested mode
MOVE.B #oneBitMode,spId(A0) ; pass the default mode (assumed to be 1-bit mode)
_sFindStruct ; point to this mode information
MOVE.B #mVidParams,spID(A0) ; now get the device pixmap
_sGetBlock ; on the current heap (system normally here)
MOVE.L spResult(A0),A1 ; get the result pointer
MOVE.w vpRowBytes(A1),screenRow ; get the screen row bytes (WORD)
; Set up the low-mem for screen resolution too. Theyre only WORD/WORD rather then FIXED/FIXED.
;
MOVE.W vpHRes(A1),ScrHRes ; Take the high word of vpHRes
MOVE.W vpVRes(A1),ScrVRes ; Take the high word of vpVRes
MOVE.L spResult(A0),A0 ; Do what it says in IM V (p 446) instead of
_DisposPtr ; of using _sDispose. <12>
@InitGD MOVE D1,-(SP) ; push refnum
MOVE (A4)+,-(SP) ; push mode
CLR -(SP) ; which should be long
MOVE.L A3,-(SP) ; push gDevice
_InitGDevice ; configure the gDevice
ADDQ #4,A4 ; mask and flags already used
; If there is a gamma table resource id, get the gamma correction table and call the driver.
; We need to do this before setting the color table (via SetEntries) to make sure it takes
; effect right away.
;
MOVE 2(A4),D0 ; get the gamma table resource id
CMP #-1,D0 ; is it -1?
BEQ.S ChkTbl ; => yes, no table
; If the gamma table resource id = -2, then request linear gamma from the driver.
;
CMP #-2,D0 ; is it -2?
BNE.S @GetFromSys ; nope, so load the system resource
;+++ LEA VidParms(A6),A1 ; point to parameter block
;+++ CLR.L csGTable(A1) ; pass NIL to tell new drivers to set linear
;+++ BSR.S GammaControl ; call a common routine to set gamma
; <19>: Use SetDevGamma instead of GammaControl
;
Move.l A3,A0 ; Put gDevice in A0 for SetDevGamma call.
Move.l #0,A1 ; (nil) gammaTable Ptr in A1 (to set linear).
Bsr.s SetDevGamma
;
BRA.S ChkTbl
; Load the gamma resource from the system and set it.
;
@GetFromSys CLR.L -(SP) ; make room for function result
MOVE.L #'gama',-(SP) ; push gamma table rsrc type
MOVE D0,-(SP) ; else push resource id
_GetResource ; try to read in gamma table
MOVE.L (SP)+,D0 ; get the result
BEQ.S ChkTbl ; => couldn't find it, use default
MOVE.L D0,-(SP) ; save a copy for later
MOVE.L D0,A0 ; setup for HLock
_HLock ;
;+++ LEA VidParms(A6),A1 ; point to params for SetGamma
;+++ MOVE.L (A0),csGTable(A1) ; gamma table pointer is only param
;+++ BSR.S GammaControl ; call a common routine
; <19>: Use SetDevGamma instead of GammaControl. For <23>, the setup for the
; SetDevGamma call was backwards.
;
Move.l (A0),A1 ; Put pointer to gammaTable in A1, and
Move.l A3,A0 ; put pointer to GDevice in A0.
Bsr.s SetDevGamma
;
MOVE.L (SP),A0 ; get the resource handle back
_HUnlock ; free it
_ReleaseResource ; and release it (fixing the stack)
; <19>: Commented out GammaControl as it is replaced by the SetDevGamma utility
; above. Also, the branch around the GammaControl routine is commented
; out.
;
;+++ BRA.S ChkTbl ; continue on
;
; Here's an imbedded utility. I know I burn 2 bytes always BSRing around it, but I
; would burn two with a word branch if the utility were outside. This routine sets
; up the iopb and csParam block for a SetGamma control call. It expects the csGTable
; field to be set up, the csParam block pointer in A1, and the gdevice pointer in A3.
;
;GammaControl
;
; LEA IOPBlk(A6),A0 ; point to parameter block
; MOVE.L A1,csParam(A0) ; move addr of parms into block
; MOVE.W #cscSetGamma,csCode(A0) ; cscSetGamma <12>
;+++ CLR.L ioCompletion(A0) ; no completion routine <16>: not necessary
;+++ CLR.W ioVRefNum(A0) ; no volRefNum <16>: not necessary
; MOVE.L (A3),A1 ; point to gdevice
; MOVE GDRefNum(A1),ioRefNum(A0) ; set device's refnum
; _Control ,IMMED ; SetGamma(GammaTable)
; ; if error here (likely if -2 were passed to
; ; and old driver) then just use default table
; RTS ; and back
;
;
; Previously, if there was a color table resource id, this part loaded that table. Now,
; it checks the state of the gdDevType bit. If it is monochrome (=0), then this routine
; substitutes pixelSize+32 for the resID. If it is color (=1) and in 2- or 4-bit mode, then
; pixelSize+64 is substituted to yield a modified color table that includes the highlight
; color.
;
; If we EVER have a gamma ID <> -1 (not default), then be sure to set the color table
; to flush this gamma into the CLUT hardware.
;
; The pointer to the gDevice is still in A1.
;
;
ChkTbl
MOVE.L (A3),A1 ; point to the gDevice again
MOVE.L gdPMap(A1),A0 ; get pixmap
MOVE.L (A0),A0 ; get pixmap ptr
MOVE.W pmPixelSize(A0),D0 ; get depth
CMP #directType,gdType(A1) ; is it a direct/fixed device?
BEQ.S SetGRect ; if so, then do nothing <19>:s
BTST #gdDevType,gdFlags+1(A1) ; is it color or monochrome mode?
BNE.S @ClrMode ; if set, then this is color
CMP.W #2,D0 ; 1 or 2 bit/pixel?
BLE.S @RegClr ; don't do anything funky
@MonoMode
ADD #32,D0 ; add 32 to pixelsize in all modes for linear gray
BRA.S @GetClut ;
@ClrMode
MOVE.W D0,D1 ; copy the depth
AND #9,D1 ; is it 1- or 8-bit mode?
BNE.S @RegClr ; if so, then do regular behavior
@Is2or4
ADD #64,D0 ; for 2- or 4-bit, add 64 to pixel depth (gives color+highlight)
;!!! BRA.S @GetClut ;
@RegClr
;!!! MOVE (A4),D1 ; get the color table resource id
;!!! CMP #-1,D1 ; is it -1?
;!!! BNE.S @GetClut ; if not, then set the CLUT
;!!! CMP #-1,2(A4) ; if CLUTid=-1, and gammaID<>-1, then set CLUT to flush
;!!! BEQ.S SetGRect ; if both are default, then continue
@GetClut CLR.L -(SP) ; make room for function result
MOVE D0,-(SP) ; push resource id
_GetCTable ; get a color table
MOVE.L (SP)+,D0 ; get the result
BEQ.S SetGRect ; => couldn't find it, use default
MOVE.L D0,A0 ; save source handle in A0
MOVE.L (A3),A1 ; point at the gDevice
MOVE.L gdPMap(A1),A1 ; get handle to its pixMap
MOVE.L (A1),A1 ; point at the pixMap
MOVE.L pmTable(A1),A1 ; get handle to existing color table
MOVE.L A1,-(SP) ; push the color table for later
MOVE.L A0,-(SP) ; push new table handle for dispose
_GetHandleSize ; get the source size
MOVE.L D0,D1 ; save size in D1
EXG A0,A1 ; get dest handle in A0
_SetHandleSize ; set the dest handle size
EXG A0,A1 ; swap dest back to A1, src to A0
MOVE.L (A0),A0 ; get source ptr
MOVE.L (A1),A1 ; get dst ptr
MOVE.L D1,D0 ; get size to move
_BlockMove ; copy it
_DisposCTable ; and dispose new handle
; Now call the driver to set this color table (handle on stack)
; <19>: Use SetDevEntries call instead of in-line code.
;
Move.l A3,A0 ; A0 contains gDevice.
Move.l (Sp),A1 ; A1 contain colorTable Handle
Bsr.s SetDevEntries ;
; MOVE.L (SP),A0 ; get handle to color table
; _HLock ; lock down the color table
; LEA VidParms(A6),A1 ; point to params for SetEntries
; MOVE.L (A0),A0 ; get ctabPtr
; CLR.W csStart(A1) ; start at zero, use sequence mode
; MOVE.W ctSize(A0),csCount(A1) ; for the length of the table
; LEA ctTable(A0),A0 ; get pointer to colorspecs
; MOVE.L A0,csTable(A1) ; color table pointer is first param
; LEA IOPBlk(A6),A0 ; point to parameter block
; MOVE.L A1,csParam(A0) ; move addr of parms into block
; MOVE.W #cscSetEntries,csCode(A0) ; cscSetEntries <12>
;+++ CLR.L ioCompletion(A0) ; no completion routine <14>: not necessary
;+++ CLR.W ioVRefNum(A0) ; no volRefNum <14>: not necessary
; MOVE.L (A3),A1 ; point to gdevice
; MOVE gdRefNum(A1),ioRefNum(A0) ; set device's refnum
; _Control ,IMMED ; do a SetEntries on color table
;
; MOVE.L (SP),A0 ; get handle to color table
; _HUnLock ; unlock the color table
; Finally, generate an inverse table for the table (handle on stack)
;
MOVE.L (A3),A1 ; point at the gDevice
MOVE.L gdITable(A1),-(SP) ; push inverse table handle
MOVEQ #4,D0 ; make 4-4-4 inverse tables
MOVE D0,gdResPref(A1) ; save in GDevice
MOVE D0,-(SP) ; and push res
_MakeITable ; and generate inverse table (color/inverse table handles still on stack)
; Use the specified rectangle to determine the device's global coordinates
;
SetGRect
ADDA #4,A4 ; skip the CLUT and gamma resID's
MOVE.L (A3),A0 ; point to the grafDevice
MOVE.L gdPmap(A0),A1 ; get handle to pixMap
MOVE.L (A1),A1 ; get pointer to pixMap
ADDQ #bounds,A1 ; point to pixMap.bounds
LEA gdRect(A0),A0 ; point to its rectangle
MOVE.L (A4)+,D0 ; get topLeft for mouse offset
MOVE.L D0,(A1)+ ; copy topLeft to pixMap.bounds
MOVE.L D0,(A0)+ ; copy topLeft to GDRect
MOVE.L (A4),(A1) ; copy botRight to pixMap.bounds
MOVE.L (A4)+,(A0)+ ; copy botRight to GDRect
; Parse and execute the additional control commands
;
MOVE (A4)+,D6 ; get number of control calls
BRA.S ChkNxtCtl ; => jump into end of dbra loop
DoCtl LEA IOPBlk(A6),A0 ; point to parameter block
LEA 4(A4),A1 ; point to call parameters
MOVE.L A1,csParam(A0) ; move addr of parms into block
MOVE.W (A4)+,csCode(A0) ; set control code
;+++ CLR.L ioCompletion(A0) ; no completion routine <14>: not necessary
;+++ CLR.W ioVRefNum(A0) ; no volRefNum <14>: not necessary
MOVE.L (A3),A1 ; point to gdevice
MOVE gdRefNum(A1),ioRefNum(A0) ; set device's refnum
_Control ,IMMED ; and issue the control call
MOVE (A4)+,D0 ; get size of param block
ADD D0,A4 ; skip param block
ChkNxtCtl DBRA D6,DoCtl ; loop for all control calls
ChkNxt DBRA D7,DoNxt ; loop for all screens in resource
MOVE.L MainDevice,a0
move.l a0,CrsrDevice ; cursor is now on main device, no longer on boot device
import GetDCtlEntry
subq #4,sp ; room for resulting DCE handle
move.l (a0),a0
move.w gdRefnum(a0),-(sp) ; get the refNum
jsr GetDCtlEntry
move.l (sp)+,a0 ; get handle to DCE
move.l (a0),a0 ; get pointer to DCE
move.l #0,d0 ; clear out D0
move.b dCtlSlot(a0),d0 ; get the slot number
_AttachVBL ; attach VBL to this slot
CLR.B CrsrBusy ; end of change
_AllocCursor ; make sure all cursor structs are updated
_ShowCursor ; now redisplay cursor
ScrnDone _ReleaseResource ; all done with the resource <19>: Done -> ScrnDone
; ••• 4th INIT •••
;
; As explained above in the SixPack update notes, the NoGammaFix is for $067C-class
; machines only. The function of this code is to seek out non-TFB video cards that
; do not have gamma directories. When such cards are found, they are issued a
; SetDevGamma call with the ROMs default gamma table.
;
; [This should just be fixed in the SuperMario CQD sources directly.]
;
NoGammaFix
Move.l ROMBase,A0 ; Point to ROMBase with A0.
If Not ForROM Then
Cmp.w #$067C,8(A0) ; If were not running on a $67C
Bne GoHome ; ROM, then just go on.
Else
Cmp.w #$077D,8(A0) ; If were not running on a $77D
Bne GoHome ; ROM, then just go on.
Endif
; Get the default gamma table from ROM (so we dont have to get it every time
; we find a card that needs it -- if we dont find any cards that need
; to be fixed, no harm done).
;
Clr.l -(Sp) ; Make an RGetResource('gama',0) call.
Move.l #'gama',-(Sp) ; resType = 'gama'
Clr.w -(Sp) ; resID = 0
_RGetResource ; (RGetResource exists on $067C machines.)
; Since this is a ROM resource, I assume that the _RGetResource will NOT fail. Is
; this a bad assumption? (Ive seen several places in various other OS files that
; make the same assumption, but I wont name any names.)
Move.l (Sp),-(Sp) ; Transform the 'gama' resource into
_DetachResource ; a Handle, and prevent it from
Move.l (Sp)+,A0 ; being purged.
_HNoPurge
Move.l A0,A2 ; Keep a copy of the gammaTable Handle
; in A2 for future reference.
; Walk thru the gDevice list looking for non-TFB video cards that do not have
; gamma directories. (Note: Dave F. suggested that I do this via the Slot
; Manager but I thought that since gDevices have already been set up and
; since they are easier to walk thru, I would just use them instead.)
Move.l DeviceList,A3 ; Use A3 to keep the gDevice Handle, and
@nextGD Move.l A3,A4 ; A4 to keep the gDevice Ptr.
Move.l (A4),A4 ;
Move.w gdRefNum(A4),D0 ; Get the gDevices slotID by looking
Not.w D0 ; it up in the UnitTable.
Move.l UTableBase,A0 ;
Move.l (A0,D0*4),A0 ; DCE Handle.
Move.l (A0),A0 ; DCE Ptr.
Move.b dCtlSlot(A0),D0 ; Save slot number.
Lea SlotParms(A6),A0 ; Fill out SpBlock:
Move.b D0,spSlot(A0) ; spSlot = slot number
Clr.w spID(A0) ; spID = 0
Clr.w spExtDev(A0) ; spExtDev = 0
Move.b #drvrHWMask,spTBMask(A0) ; spTBMask = drvrHWMask
Move.w #catDisplay,spCategory(A0) ; spCategory = catDisplay
Move.w #typVideo,spCType(A0) ; spCType = typVideo
Move.w #drSwApple,spDrvrSW(A0) ; spDrvrSW = drSwApple
Clr.w spHwDev(A0) ; spHwDev = 0;
_SNextTypeSRsrc ; Was there an Apple SW compatible video card here?
Bne.s @skipGD ; Apparently not, so skip this device.
Cmp.w #drHwTFB,spDrvrHW(A0) ; If there is a card here, is it a TFB?
Beq.s @skipGD ; Yep, so skip it.
Move.b #sGammaDir,spID(A0) ; Not a TFB, so does it have a gamma
_SFindStruct ; directory associated with?
Beq.s @skipGD ; Yep, so skip it.
; We found a non-TFB card that contains no gamma table directory. So, we need to
; employ our fix, which is to make a SetGamma and then a SetEntries call.
Move.l A2,A0 ; Lock down the gammaTable Handle.
_Hlock
Move.l (A0),A1 ; gammaTable Ptr into A1.
Move.l A3,A0 ; gDevice Handle into A0.
Bsr SetDevGamma
Move.l A2,A0 ; Unlock gammaTable Handle.
_HUnlock
Move.l A3,A0 ; gDevice Handle into A0.
Move.l #-1,A1 ; Use gDevices PixMap for colorTable.
Bsr SetDevEntries
@skipGD Move.l gdNextGD(A4),D0 ; Get the next gDevice. And if
Move.l D0,A3 ; were not at the end of the
Bne.s @nextGD ; list, go around again.
Move.l A2,A0 ; Dispose of the storage used for the
_DisposHandle ; gammaTable Handle.
GoHome
;+++ MOVEM.L (SP)+,D6-D7/A2-A4 ; restore work registers
MOVEM.L (SP)+,A0-A6/D0-D7 ; so we dont screw up the boot process
UNLK A6
; ••• 5th INIT •••
;
;----------------------------------------------------------------
;
; Here's the other init in the file. It scans the device list frame buffers
; and sets a flag in the gDevice if the frame buffer is addressed in 32-bit
; mode. It's kind of slobby looking to hook this onto the end of the other
; init instead of integrating, but it's small, and the CheckDevices code
; goes to great lengths to exit early when it can, which this cannot do.
;
;----------------------------------------------------------------
;
; Yet a another function co-exists with the others in this file. If we recognize
; an Apple Video card who's interrupt handler needs to be fixed, we will do it here.
; Here's the problem: In an attempt to simplify the driver code while correcting some
; of my VBL polling code, I raised the interrupt level to level-7 while waiting for
; the leading edge of VBL. Unfortunately, this can lead to a (eternally long) wait
; of up to one active screen for the next leading edge. In earlier versions, I
; forced the SR to $2200 which got level-2 interrupts (good) and forced the interrupt
; stack pointer (bad). When the interrupt level is raised to level-7, the SCC and
; everything else is blocked out which can cause loss of data on the serial ports.
; This new replacement code will raise the level to level-2 if it isn't higher already
; but won't change it if it is 3 or higher. This code is quite a bit larger than the
; original code, but fortunately, the drivers are all in RAM, so it's easy to patch
; them all out.
;
; We modify four different types of drivers. All drivers share the same faulty code,
; so we fix them all by installing a single copy of the updated interrupt code in the
; system heap, identifying which drivers are subject to patch, then pointing them at the
; new interrupt code. We identify the drivers via a few bytes of code that have significant
; values such as the name strings. We don't need to do a full compare, or check version
; numbers since we will verify the object code in the driver as well. If the faulty code
; isn't there, then we don't have to replace it! The drivers are always locked, so this
; is pretty safe (they must be locked since the interrupt handler is included within the
; driver proper).
;
; Here are the video cards modified:
; 1) Mac IIci Built-In Video Driver (.Display_Video_Apple_RBV1) [Only when this code is built as a patch.]
; 2) Mac II High-Resolution Video Card (.Display_Video_Apple_HRVC)
; 3) Mac II Two-Page Video Card (.DrWVC) [ROM Version WVC1.2, P/N 341-0727]
; 4) Mac II Portrait Video Card (.DrPVC) [ROM Version PVC1.1, P/N 341-0732]
;
BRA.S DoDrvrPatches ; Stupid extra branch because I calculate the size of the
; resident interrupt handler from labels, and they can't
; be forward references. <15>: Changed name from Start to
; DoDrvrPatches for <17>.
;----- Memory/ROM-Resident Interrupt Handler Patch ------
;
; Here is the improved interrupt level setting code. It's a little weird looking since I
; had to patch the MOVE.W SR,-(SP) to have room for the JSR, but I couldn't save any
; registers on the stack, and couldn't trash any regs either.
;
; All registers preserved (except SR!). This routine returns with the SR pushed on the top of
; stack.
;
PtchStart
SUBA.W #2,SP ; make room for the stack manipulations
MOVE.L 2(SP),(SP) ; move the retaddr to top, leaving room for SR
MOVE.W SR,4(SP) ; save the status reg
MOVE.L D0,-(SP) ; save this reg
MOVEQ #7,D0 ; get mask in D0
AND.B 8(SP),D0 ; get the interrupt level
SUBQ.B #2,D0 ;
BGE.S @OK ; if ≥, then don't change
ORI.W #$0200,SR ; raise above level-2
ANDI.W #$FAFF,SR ; make it level-2
@OK
MOVE.L (SP)+,D0 ; restore saved register
RTS ; return to caller
PtchEnd
;----------------------------------------------------
WITH spBlock,vpBlock
DoDrvrPatches
;
; Save all registers to prevent problems with the ROM INIT running code.
;
MOVEM.L A0-A6/D0-D7,-(SP) ; so we dont screw up the boot process
;
; Point to UnitTable in A2.
;
MOVE.L UTableBase,A2 ; point to base of unit table
;
; Allocate a spBlock (slot parameter block) on the stack.
;
SUB.W #spBlockSize,SP ; create an spBlock on the stack
;
; Set up stuff for the interrupt patch.
;
LEA TargetObj1,A0 ; point to the start of the target sequence
MOVE.W (A0),D6 ; get the first word of the target sequence
MOVE.L 2(A0),D7 ; get the remaining long of the target seq
MOVEQ #0,D5 ; if D5>0 at end, at least one card got patched
;
; It's easier to allocate the patch's memory and release it if it's not used than to allocate on
; demand. This is only a small piece of memory anyway.
;
If Not ForROM Then
MOVE.L #PtchEnd-PtchStart,D0 ; get the size of the interrupt fixer
_NewPtr ,Sys ; allocate some memory for it in sysheap
BNE Out ; if you can't get memory, exit
LEA PtchStart,A1 ; point at the code
EXG A1,A0 ; get source in A0, dest in A1
MOVE.L #PtchEnd-PtchStart,D0 ; get the size of the interrupt fixer
_BlockMove ; copy it down
Endif
LEA ReplObj,A6 ; point to the substitution object
If Not ForROM Then
MOVE.L A1,2(A6) ; patch the JSR address with the sysHeap dest
Endif
;
; Get a pointer to the first gDevice in A3. Since we won't upset memory, we don't need to lock it.
;
MOVE.L DeviceList,A3 ; get handle
MOVE.L (A3),A3 ; get pointer
;
; Point to DCE of next gDevice
;
NxtSlotLoop
MOVE.W gdRefNum(A3),D0 ; get driver refnum
NOT.W D0 ; convert to offset
MOVE.L (A2,D0*4),A1 ; get DCE handle
MOVE.L (A1),A1 ; get DCE pointer
MOVE.L A1,A4 ; save this for driver patching code below
;
; Point to spBlock.
;
MOVE.L SP,A0 ; save pointer to block
;
; Set up for an sRsrcInfo call.
;
MOVE.B dCtlSlot(A1),spSlot(A0) ; get slot number
MOVE.B dCtlSlotID(A1),spID(A0) ; get ID
MOVE.B dCtlExtDev(A1),spExtDev(A0) ; external device ID
_sRsrcInfo ; there should never be a miss here
;
; Now that we have the right sRsrcList in spsPointer, get the sRsrcFlags word
; from the video sRsrc.
;
MOVE.B #sRsrcFlags,spID(A0) ; look for sRsrcFlags
_sReadWord ; spsPointer is still set up from before
BNE.S @IntPtch ; if not present, then it's 24-bit addressed
MOVE.L spResult(A0),D0 ; get the result in a reg
;
; Test the flag word for 32-bit devices
;
BTST #f32BitMode,D0 ; test it
BEQ.S @IntPtch ; if not a 32-bit device, don't do init
BSET #ext32Device,gdFlags(A3) ; set the 32-bit access flag in the gDevice
;
; Take the DCE pointer in A4 (from above), and test to see if we want to patch this driver.
;
@IntPtch
If Not ForROM Then
BTST #dRAMBased,dCtlFlags+1(A4) ; test if this is a driver in ROM (Erickson overpatch) <7.0>
BEQ NxtSlot ; if so, then continue to next slot <7.0>
Endif
MOVE.L dCtlDriver(A4),A1 ; get handle to driver
MOVE.L (A1),A1 ; get pointer to driver
MOVE.L drvrName+2(A1),D0 ; get a unique long from the name
CMP.L #'DrWV',D0 ; is it the 2-Page card?
BEQ.S @isTwo ;
CMP.L #'DrPV',D0 ; is it the Portrait card?
BEQ.S @isPort ;
CMP.L #'Disp',D0 ; could it be one of the others?
BNE NxtSlot ; no, so don't do anything with this card
MOVE.L drvrName+20(A1),D0 ; pick up the next significant long
CMP.L #'e_HR',D0 ; is it the Hi-Res Video card?
BEQ.S @isHR ;
If Not ForROM Then
CMP.L #'e_RB',D0 ; is it the Mac II ci?
BNE.S NxtSlot ; no, so go to the next card
Else
Bra.s NxtSlot
Endif
; Here are the patch offsets for the Mac IIci Built-In Video v1.0 driver.
If Not ForROM Then
MOVE.W #$1A4,D0 ; pass the offset <Control-SetVidMode>
BSR CmpReplTarget1 ; (compare and replace) or exit to NxtSlot if no match
MOVE.W #$2C0,D0 ; <Control-SetEntries>
BSR CmpReplTarget1 ;
MOVE.W #$656,D0 ; <Utility-WaitVSync>
BSR CmpReplTarget1 ;
BRA.S @IncFlag ; and exit
Endif
;
; Since the Two-Page v1.2 and Portrait v1.1 are generated from the same source file, the offsets are the
; same. Earlier releases of these two ROMs don't have this interrupt problem.
;
@isTwo ;
@isPort
MOVE.W #$2DA,D0 ; pass the offset <Control-SetVidMode>
BSR CmpReplTarget1 ; (compare and replace) or exit to NxtSlot if no match
MOVE.W #$388,D0 ; <Control-SetEntries/nonsequential>
BSR CmpReplTarget1 ;
MOVE.W #$4D8,D0 ; <Control-SetEntries/sequential>
BSR CmpReplTarget1 ;
MOVE.W #$630,D0 ; <Control-DisableVGuts>
BSR CmpReplTarget1 ;
MOVE.W #$8CC,D0 ; <Utility-TFBSetDepth>
BSR CmpReplTarget1 ;
BRA.S @IncFlag ; and exit
;
; Here are the patch offsets for the Mac II Hi-Res Video Card v1.0. I missed updating one case of the
; interrupt disabling code, so there is one special patch for that missed case.
;
@isHR
MOVE.W #$45A,D0 ; pass the offset <Control-SetVidMode>
BSR CmpReplTarget1 ; (compare and replace) or exit to NxtSlot if no match
MOVE.W #$58A,D0 ; <Control-SetEntries>
BSR CmpReplTarget1 ;
MOVE.W #$6F2,D0 ; <Control-DisableVGuts>
BSR CmpReplTarget1 ;
BSR CmpReplTarget2 ; here's the one odd case <Utility-WaitVSync>
MOVE.W #$A1E,D0 ; <Control-TFBSetDepth>
BSR CmpReplTarget1 ;
@IncFlag ADDQ #1,D5 ; increment patching flag
NxtSlot
MOVE.L gdNextGD(A3),D0 ; get handle to next gDevice
MOVE.L (ZA0,D0.L),A3
BNE NxtSlotLoop
;
; See if the any drivers were patched. If not, then release the patcher block in sysheap.
;
If Not ForROM Then
TST.B D5 ; if zero, then nobody was patched
BNE.S Out ;
Out1 LEA ReplObj,A6 ; point to the substitution object
MOVE.L 2(A6),A0 ; get the pointer block address from here
_DisposPtr ; release it
Endif
;
; Release the slot manager block.
;
Out ADD.L #spBlockSize,SP ; clean up the stack
Endwith
;
; Lets restore more registers than have ever been restored before. (Hey, you can never be too careful.)
;
MOVEM.L (SP)+,A0-A6/D0-D7 ; so we dont screw up the boot process
; ••• 7th INIT •••
;
If Not ForROM Then
;---------------------------------------------------------------------
; Local variables, definitions, etc....
;---------------------------------------------------------------------
drHwDAFB Equ $001C ; Built-in Video Hardware ID for Macintosh Quadras 700/900/950.
DrvrVer950 Equ $0001 ; Version number of the Macintosh Quadra 950s video driver.
badEntry Equ $38 ; Location of bad table entry in the Macintosh Quadra 950 driver.
; Straight from the Macintosh Quadra 950 ROMs source code…
;
DAFBVidPrivates RECORD 0
saveBaseAddr DS.L 1 ; the screen base address (NOT ST corrected!)
saveScreenBase DS.L 1 ; ST corrected version of saveBaseAddr.
saveSQElPtr DS.L 1 ; the SQ element pointer (for _SIntRemove)
saveGammaPtr DS.L 1 ; the pointer to the Gamma correction table
saveGamDispPtr DS.L 1 ; the pointer to the Gamma block
saveVDACBase DS.L 1 ; the base addr of the VDAC
saveDAFBBase DS.L 1 ; the base addr of the DAFB
saveVidPtr DS.L 1 ; pointer to a big block of DAFB video parameters
GFlags DS.W 1 ; flags word
has16bppACDC Ds.b 1 ; true if AC842A is around
pageModeSet Ds.b 1 ; true if the pRam PageMode enable bit is set
saveMode DS.W 1 ; the current mode setting (in lo-byte)
saveMonID DS.W 1 ; monitor type ID (in lo-byte)
saveSlotId DS.W 1 ; spID of video sRsrc (hi-order byte only!)
DAFBVidPrivSize EQU *
ENDR
; Flags within GFlags word…
;
GrayFlag EQU 15 ; luminance mapped if GFlags(GrayFlag) = 1
IntDisFlag EQU 14 ; interrupts disabled if GFlags(IntFlag) =1
IsMono EQU 13 ; true if monochrome only display (Portrait/Kong)
UseSeq EQU 12 ; true if sequence mode SetEntries
UseTrans Equ 12 ; True if were supposed to translate 5-bit into 8 (DAFB 16bpp).
Is16 EQU 11 ; true if 16Mhz (Slow) CPU
IsSlow Equ 11 ; True if Slow CPU (for DAFB, 25Mhz is slow).
IsDirect EQU 10 ; true if direct video mode, else chunkyIndexed
PsuedoIndex EQU 9 ; true if SetEntries request was mapped to indexed from sequential
; (due to screen depth hardware requirements)
Has16bppSRsrc Equ 9 ; True if FifthVidMode is 16bpp instead of 32bpp (DAFB).
SyncOnGreen Equ 8 ; True if were supposed to put sync on green (DAFB).
bra.s PatchQuadra950Driver ; skip over the title
String Pascal
DAFBVideoTitle Dc.b '.Display_Video_Apple_DAFB'
Align 2
;---------------------------------------------------------------------
; Main
;---------------------------------------------------------------------
PatchQuadra950Driver
String AsIs
With SpBlock,DAFBVidPrivates
Quadra950SaveRegs Reg D4-D6 ; Define work registers.
If AsInit Then
Cmp.w #$3FFF,ROM85 ; If Color QuickDraw is not around,
Bne @ExitNow ; then just leave.
EndIf
Tst.l DeviceList ; If the device list is empty,
Beq @ExitNow ; then just leave.
Move.l DeviceList,A0 ; Get the DeviceList Handle.
Move.l (A0),A0 ; Make it a pointer.
Move.w gdRefNum(A0),D0 ; If theres no driver, then
Beq @ExitNow ; we cant do anything here.
Movem.l Quadra950SaveRegs,-(Sp) ; Save work registers.
Suba.w #spBlockSize,Sp ; Allocate SpBlock
; The shipping version of the Macintosh Quadra 950s ROM (1.7F2) has a bug in the built-in video
; driver which prevents the DirectSetEntries call from working correctly when the attached display
; is put into 32 bit-per-pixel mode. To fix this problem, we just patch the bad table in place
; since it resides in the System heap.
;
Move.l Sp,A0 ; Get spBlock ptr into A0.
Clr.b spId(A0) ; Begin at id 0.
Clr.b spSlot(A0) ; We only care about Slot $0.
Clr.b spExtDev(A0) ; No external device.
Clr.b spTBMask(A0) ; No mask in search.
Move.w #catDisplay,spCategory(A0) ; Look for: Display,
Move.w #typVideo,spCType(A0) ; Video,
Move.w #drSwApple,spDrvrSW(A0) ; Apple,
Move.w #drHwDAFB,spDrvrHW(A0) ; DAFB.
Clr.l spParamData(A0) ; Look only for enabled sRsrcs.
Bset #foneslot,spParamData+3(A0) ; Limit search to this slot only.
_GetTypeSRsrc ; If built-in video is not enabled, then
Bne.s @AllDone ; just quit.
; We found the DAFB-based (Macintosh Quadra 700/900/950) built-in video in Slot $0.
;
Moveq #0,D5 ; Prepare D5.
Move.w spRefNum(A0),D5 ; Get the refNum.
Beq.s @AllDone ; If nil, then just leave (no driver).
Not.w D5 ; Convert the refNum into…
Lsl.w #2,D5 ; …a UTable index.
Add.l UTableBase,D5 ; Get a ptr to the AuxDCEHandle.
Move.l D5,A0 ; Get it into A0.
Move.l (A0),A0 ; Get the AuxDCEHandle.
Move.l (A0),A0 ; Get the AuxDCEPtr.
Move.l A0,D5 ; Save it for later.
move.w dCtlFlags(a0),d0 ; <27> Get driver flags
Move.l dCtlDriver(A0),A0 ; Get driver.
btst #dRAMBased,d0 ; <27> Check to see if dCtlDriver is a handle or a pointer
bz.s @gotDriverPointer ; <27> A ROM based driver means its a pointer
Move.l (A0),A0 ; Get ptr to driver.
@gotDriverPointer
Move.l A0,D6 ; Save it for later.
Moveq #0,D0 ; Prepare D0.
Lea drvrName(A0),A0 ; Point to the driver name.
Move.l A0,D4 ; Save it for later.
Move.b (A0)+,D0 ; Get its length.
Swap D0 ; Save it.
Lea DAFBVideoTitle,A1 ; Point to the driver name we want.
Move.b (A1)+,D0 ; Get its length.
_CmpString ; Compare the names.
Tst.w D0 ; If they are not equal, then we dont know about
Bne.s @AllDone ; this DAFB driver, so just leave.
Moveq #0,D0 ; Re-prepare D0.
Move.l D4,A0 ; Re-point to the driver name.
Move.b (A0),D0 ; Get its length.
Addq #2,D0 ; Adjust offset to version field.
Bclr #0,D0 ; Adjust offset for word alignment.
Move.w (A0,D0),D4 ; Get the drivers version number.
Cmp.w #DrvrVer950,D4 ; If this isnt the Quadra 950s driver version,
Bne.s @AllDone ; then just leave.
Adda.w D0,A0 ; Point to version part of driver name.
Move.l A0,D4 ; Save it for later.
; We found the Macintosh Quadra 950s version of the DAFB driver.
;
Move.l D5,A0 ; Re-point to the AuxDCEPtr.
Move.l dCtlStorage(A0),A0 ; Get the Handle to DAFB private storage.
Move.l (A0),A0 ; Make it a pointer.
Btst #Has16bppSRsrc,GFlags(A0) ; If a 16bpp-capable sRsrc is not in use,
Beq.s @AllDone ; then just leave.
Move.l D6,A0 ; Re-point to the DAFB driver.
Move.b #$FF,badEntry(A0) ; Fix the bad table entry.
Move.l D4,A0 ; Re-point to the DAFB driver version number.
Move.w #DrvrVer950+1,(A0) ; Update it.
@AllDone
Add.w #spBlockSize,Sp ; Deallocate SpBlock.
Movem.l (Sp)+,Quadra950SaveRegs ; Restore work registers.
@ExitNow ; Outta here, dudes.
Rts
Endwith
Else
Rts
Endif
;
; This compares the object code at (A1,D0.W) with the target string in D6 and D7, then, if it
; matches, replaces this object with a JSR absolute. It saves a little code in the patch
; since this is a very common sequence.
;
CmpReplTarget1
CMP.W (A1,D0.W),D6 ; is this the target string
BNE.S ExitBad ; no, so quit
CMP.L 2(A1,D0.W),D7 ; check the other half
BNE.S ExitBad ; no, so quit
; Replace the faulty code
;
MOVE.W (A6),(A1,D0.W) ; copy the JSR instruction
If ForROM Then
Lea PtchStart,A5 ; Get a pointer to the start of the replacement code.
Move.l A5,2(A1,D0.W) ; And copy it down.
Else
MOVE.L 2(A6),2(A1,D0.W) ; copy the patch address
Endif
ExitGood RTS ; return
ExitBad ADDA #4,SP ; kill return address
BRA NxtSlot ; and go to next card
;
; This compares the HRVC's odd case object code at (A1,D0.W) with TargetObj2, then, if it
; matches, replaces this object with a JSR absolute.
;
CmpReplTarget2
MOVE.L A0,-(SP) ; save some regs
LEA TargetObj2,A0 ; point to the target object
MOVE.L (A0)+,D1 ; get the first long
CMP.L $9BA(A1),D1 ; is this the target string
BNE.S ExitBad2 ; no, so quit
MOVE.L (A0)+,D1 ; get the second long
CMP.L $9BA+4(A1),D1 ; check the other half
BNE.S ExitBad2 ; no, so quit
MOVE.W (A0)+,D1 ; get the final word
CMP.W $9BA+8(A1),D1 ; check the other half
BNE.S ExitBad2 ; no, so quit
; Replace the faulty code
;
MOVE.W (A6),$9BA(A1) ; copy the extended patch over
If ForROM Then
Lea PtchStart,A5 ; Get a pointer to the start of the replacement code.
Move.l A5,$9BA+2(A1) ; And copy it down.
Else
MOVE.L 2(A6),$9BA+2(A1) ; copy the patch address
Endif
MOVE.L 6(A6),$9BA+6(A1) ; copy some NOPs for fill out the gap
MOVE.L (SP)+,A0 ; restore A0
ExitGood2 RTS ; return
ExitBad2
MOVE.L (SP)+,A0 ; restore A0
ADDA #4,SP ; kill return address
BRA NxtSlot ; and go to next card
; Here is the faulty code section. We will replace it with a JSR to the improved code. Since
; the first line is a stack-based operation, the patch code needs to swap things around a
; bit.
;
TargetObj1 MOVE.W SR,-(SP) ; word to test
OR.W #$0700,SR ; longword to test
TargetObj2 MOVE.W SR,D0 ; longword to test
MOVE.W D0,-(SP)
OR.W #$0700,D0 ; longword to test
MOVE.W D0,SR ; word to test
;
; Here is the image of the code to replace the faulty sections.
;
ReplObj
JSR $7FFFFFFF ; the destination will be patched
NOP ; target2 needs some additional NOPs
NOP ;
END