; ; 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): ; ; 09-23-93 jmp Quit doing below when the Display Manager is around. ; 9/1/93 SKH Fixed a bug with fixed CLUT devices (ie: DBLite). SetEntries can not be called for ; direct or fixed devices ; 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. ; 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). ; 10/28/92 SWC Changed SlotEqu.a->Slots.a and VideoEqu.a->Video.a. ; 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. ; 10/27/92 CSS Changed a short branch to a word branch. ; 7/16/92 CSS Update from Reality: ; <27> 7/13/92 DTY #1035553 : 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 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), 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? BNE SetGRect ; if so, then do nothing <19>:s 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 BSR CmpReplTarget1 ; (compare and replace) or exit to NxtSlot if no match MOVE.W #$2C0,D0 ; BSR CmpReplTarget1 ; MOVE.W #$656,D0 ; 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 BSR CmpReplTarget1 ; (compare and replace) or exit to NxtSlot if no match MOVE.W #$388,D0 ; BSR CmpReplTarget1 ; MOVE.W #$4D8,D0 ; BSR CmpReplTarget1 ; MOVE.W #$630,D0 ; BSR CmpReplTarget1 ; MOVE.W #$8CC,D0 ; 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 BSR CmpReplTarget1 ; (compare and replace) or exit to NxtSlot if no match MOVE.W #$58A,D0 ; BSR CmpReplTarget1 ; MOVE.W #$6F2,D0 ; BSR CmpReplTarget1 ; BSR CmpReplTarget2 ; here's the one odd case MOVE.W #$A1E,D0 ; 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 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