boot3/QuickDraw/CheckDevicesINIT.a

1543 lines
62 KiB
Plaintext

;
; 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.
; <SM9> 9/1/93 SKH Fixed a bug with fixed CLUT devices (ie: DBLite). SetEntries can not be called for
; direct or fixed devices
; <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).
; <SM6> 10/28/92 SWC Changed SlotEqu.a->Slots.a and VideoEqu.a->Video.a.
; <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.
; <SM4> 10/27/92 CSS Changed a short branch to a word branch.
; <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 itÕs 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 (IÕll 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 itÕs 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 doesnÕt 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.
;
; IÕve 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 deviceÕs pmTable. The other problem is a little more
; subtle and only happens on $067C machines. The problem is that InitDefGamma (in StartInit)
; doesnÕt 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? DoesnÕt 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 #clutType,gdType(A2) ; If the gDevice is direct or fixed (SKH), <SM9>
Bne.s @sdeExit ; then do nothing.
Cmp.l #-1,A1 ; If A1 == -1, then use the
Beq.s @usePMap ; gDeviceÕs PixMap.
Move.l A1,A0 ; Otherwise copy the colorTable Handle
Bra.s @continue ; and continue on.
@usePMap Move.l gdPMap(A2),A0 ; Get the gDeviceÕs pixMapÕs
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 donÕt 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
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
Beq.s NoScrn ; if nil, do the no 'scrn' code
; ¥¥¥ 2nd INIT ¥¥¥
;
; Test the scrnInval low-mem to make sure the screen resource is valid. (Note: scrnInval
; will generally be cleared by the video cardÕs primaryInit IF the information in
; pRAM doesnÕt match the current set up). This is ALSO a case where we need to
; make a SetEntries call so the screen colors donÕt change on the the first SetEntries
; and/or SetGamma call.
;
ChkScrn
Tst.b scrnInval ; If the 'scrn' resource is not invalid,
Bne.s GotScrn ; then just go on.
Move.l D0,A4 ; Save the 'scrn' resource handle.
Move.l #gestaltDisplayMgrAttr,D0 ; We need to know if the Display Manager is around.
_Gestalt ; Ask, and ye shall receive.
Bne.s @NoDM ; Oops, got an error.
Move.l A0,D0 ; Get the result into D0.
Btst #gestaltDisplayMgrPresent,D0 ; If the Display Manager is around, then
Bne.s NoScrn ; donÕt dispose of the 'scrn' resource so
@NoDM ; so that the Display Manager can deal with it.
Clr.w -(Sp) ; Make room for resFile refNum.
Move.l A4,-(Sp) ; Push 'scrn' resource handle for resFile.
_HomeResFile ; Get refNum.
Move.l A4,-(Sp) ; Push 'scrn' resource handle for remove.
_RmveResource ; Try to remove it.
Tst.w ResErr ; If everything is okay, then
Beq.s @DisposeIt ; just go on.
Tst.w (Sp)+ ; Clean up the stack.
Move.l A4,D0 ; Get 'scrn' resource handle back into D0.
Bra.s GotScrn ; And weÕre screwed.
@DisposeIt Movea.l A4,A0 ; Get 'scrn' resource handle into A0.
_DisposHandle ; Dispose it.
_UpdateResFile ; Update the 'scrn's resFile lest we die later.
; If a 'scrn' resource is NOT around weÕll 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 gDeviceÕs 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 itÕs 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 letÕs 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 letÕs 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. TheyÕre 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 #clutType,gdType(A1) ; is it a direct/fixed (SKH) device? <SM9>
BNE SetGRect ; if so, then do nothing <19>:s <SM4> CSS
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 ROMÕs 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 weÕre not running on a $67C
Bne GoHome ; ROM, then just go on.
Else
Cmp.w #$077D,8(A0) ; If weÕre not running on a $77D
Bne GoHome ; ROM, then just go on.
Endif
; Get the default gamma table from ROM (so we donÕt have to get it every time
; we find a card that needs it -- if we donÕt 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? (IÕve seen several places in various other OS files that
; make the same assumption, but I wonÕt 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 gDeviceÕs 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 gDeviceÕs PixMap for colorTable.
Bsr SetDevEntries
@skipGD Move.l gdNextGD(A4),D0 ; Get the next gDevice. And if
Move.l D0,A3 ; weÕre 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 donÕt 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 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
;----------------------------------------------------
;
; 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 ;
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 donÕt 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
If Not ForROM Then
Bne Out1 ; But if there is, exit gracefully.
Else
Bne Out ; Ditto.
Endif
;
; 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
Beq.s @EndSlotLoop ; If nil, weÕre done.
Move.l D0,A3 ; Otherwise, copy the handle.
Move.l (A3),A3 ; Turn it into a pointer.
Bra.s NxtSlotLoop ; Loop until done.
@EndSlotLoop
;
; 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 LEA spBlockSize(SP),SP ; clean up the stack <SM6>
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 donÕt screw up the boot process
; ¥¥¥ 6th INIT ¥¥¥
;
if asINIT then
;
; 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.
;
; Note that for the new boot process this is no longer necessary.
;
PEA -4(A5)
_InitGraf
endif
; ¥¥¥ 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 950Õs video driver.
badEntry Equ $38 ; Location of bad table entry in the Macintosh Quadra 950 driver.
; Straight from the Macintosh Quadra 950 ROMÕs 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 weÕre 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 weÕre 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 thereÕs no driver, then
Beq @ExitNow ; we canÕt do anything here.
Movem.l Quadra950SaveRegs,-(Sp) ; Save work registers.
Suba.w #spBlockSize,Sp ; Allocate SpBlock
; The shipping version of the Macintosh Quadra 950Õs 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 itÕs 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 donÕt 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 driverÕs version number.
Cmp.w #DrvrVer950,D4 ; If this isnÕt the Quadra 950Õs 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 950Õs 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
END