mac-rom/DeclData/DeclVideo/Sonora/SonoraDriver.a

2666 lines
100 KiB
Plaintext

;
; File: SonoraDriver.a
;
; Contains: This file contains the video driver for use by the Macintosh
; OS for the Sonora hardware.
;
; Written by: Mike Puckett, December 3, 1991.
;
; Copyright: © 1991-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM20> 10/6/93 RC Added Dark Star Support by adding the Control call SetSync and
; the Status call GetSync
; <SM19> 09-23-93 jmp Made the SetDefaultMode call more Display Manager friendly.
; <SM18> 08-06-93 jmp Updated the GetConnection call to support all three types of
; multiscan display codes.
; <SM17> 08-03-93 jmp Began cleaning up the support for dynamically allocating RAM in
; PDM for video, as well as added initial support for the three
; new Apple multiscan displays.
; <16> 7/2/93 IH #1096920: Slot Manager not correctly updated in set resolution
; call. Added SUpdateSRT call.
; <15> 6/25/93 IH As per Mike's suggestion, make new Display Manager control and
; status calls clear only those fields that they use.
; <14> 6/22/93 IH Fix connection info status call.
; <SM13> 6/1/93 IH Update mode switch calls to VDSWitchInfo record and add more
; support for mode timings.
; <SM12> 5/28/93 IH Added VGA mode to MultiSync family.
; <SM11> 04-07-93 jmp Added initial low-level support for the Display Manager.
; <SM10> 04-01-93 jmp Fixed yet another bug in the GetEntries code.
; <SM9> 04-01-93 jmp Beefed-up the SetDefaultMode call to support the (hopefully)
; temporary interface to the RAM allocation on boot for video in
; PDM.
; <SM8> 3/9/93 jmp Fixed a couple of long-standing out-of-range bugs in
; Get/SetEntries, and now turn video blanking on when the video
; driver is closed.
; <SM7> 1/12/93 SAM Disabled VRAM cache flushing at every VBL on PDMs. Copyback
; VRAM just doesn't look good.
; <SM6> 11/6/92 jmp Added a little more PDM bring-up code.
; <SM5> 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
; <SM4> 11/2/92 kc Don't include SonicEqu.a.
; <SM3> 10-21-92 jmp Added code to effectively flush the copyback framebuffer for
; PDM.
; <SM2> 10-17-92 jmp Added temporary hack to support PDMÕs (broken) bring-up
; hardware.
; <SM1> 10/6/92 GDW New location for ROMLink tool.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; Pre-ROMLink comments begin here.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; <SM5> 09-29-92 jmp (jmp,H16) Fixed a problem in SetGamma where various randomly bad
; things could have occurred when going from a 3-to-1 or 1-to-3
; channel gamma tables (not something thatÕs done very often, but
; still...).
; <SM4> 09-03-92 jmp (jmp,H15) Corrected .s vs. non-.s branches and odd-alignment
; problems.
; <SM3> 6/18/92 KW (jmp,H14) Updated the Rubik 512<->560 routine to accomodate the
; Omega-2 parameters.
; <SM2> 6/4/92 KW (NJV,H13) Added new sndSonoraReverseDFAC equate in place of
; hard-coded value
; (jmp,H12) Fixed a problem where I wasnÕt always returning the
; correct frame buffer base address where I was supposed to.
; (NJV,H11) Temporarily using hard-coded $57 for DFAC Sound
; initialization to get rid of annoying playthrough.
; (NJV,H10) Fixed bug with DFAC setup for sound
; (jmp,H9) Added a small optimization to the interrupt handler.
; (JC,H8) Fix problem in Uncorrected Gamma in 16-bit mode.
; <SM1> 5/2/92 kc Roll in Horror. Comments follow:
; <H7> 04/24/92 jmp Added constants to support for the Òswitch-on-the-flyÓ Rubik-512
; to Rubik-560 and vice-versa call for DoubleExposure.
; <H6> 04/20/92 jmp In order to fully support family modes, changed the way I was
; dealing with the Rubik-560 mode in GrayScreen.
; <H5> 4/13/92 JC Replace references to SonoraAddr (it is going away) with
; references to VIA1Addr.
; <H4> 01/22/92 jmp Updated the original ÒNo ConnectÓ code to take full advantage of
; the newly-defined extended sense codes. Changed the name from
; ÒNoConnectÓ to ÒAltSense.Ó
; <H3> 01/11/92 jmp Eliminated a BoxFlag dependency.
; <H2> 12/19/91 jmp Added the initial support for Rubik-560 mode for Sonora.
; <1> 12/12/91 jmp first checked in
STRING C
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'IOPrimitiveEqu.a'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'EgretEqu.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'Video.a'
INCLUDE 'GestaltEqu.a'
INCLUDE 'SlotMgrEqu.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'DepVideoEqu.a'
PRINT ON
SEG '_sSonoraDriver'
BLANKS ON
STRING ASIS
MACHINE MC68020
; This is device storage which is stored in the dCtlStorage field of the AuxDCE.
SonoraVidPrivates RECORD 0
saveBaseAddr DS.L 1 ; the screen base address
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
saveVidPtr Ds.l 1 ; the pointer to the vidParams block
saveVDACBase DS.L 1 ; the base addr of the VDAC
saveSonoraBase Ds.l 1 ; the base addr of Sonora
GFlags DS.B 1 ; flags word (hi-order byte, actually)
noVRAM Ds.b 1 ; the no real VRAM flag
saveMode DS.W 1 ; the current mode setting
saveMonID DS.W 1 ; monitor type ID
saveSizeVRAM Ds.b 1 ; amount of vRAM/RAM
SonoraVidPrivSize EQU *
ENDR
LSonoraDriver MAIN EXPORT
;-------------------------------------------------------------------
; Video Driver Header
;-------------------------------------------------------------------
;
SonoraVidDrvr
DC.W $4C00 ; ctl,status,needsLock
DC.W 0,0,0 ; not an ornament
; Entry point offset table
DC.W SonoraVidOpen-SonoraVidDrvr ; open routine
DC.W SonoraVidDrvr-SonoraVidDrvr ; no prime in normal video drivers
DC.W SonoraVidCtl-SonoraVidDrvr ; control
DC.W SonoraVidStatus-SonoraVidDrvr ; status
DC.W SonoraVidClose-SonoraVidDrvr ; close
STRING Pascal
SonoraVidTitle
DC.B '.Display_Video_Apple_Sonora'
ALIGN 2 ; make sure we're aligned
DC.W CurSonoraDrvrVersion ; current version
STRING ASIS
;
; SonoraCLUTTbl contains information required to write to the CLUT in the different screen depths.
; Each depth's information has three values. The first is the number of entries-1 in this depth
; for range checking. The second is the address of the first active CLUT position for that
; screen depth. The last number is the ÒskipÓ factor. This is required because, in 1-4bpp, the
; entries are distributed throughout the CLUT address space. As a result, we use sequential CLUT mode
; ONLY in 8/16bpp modes. The skip factor is the address difference between adjacent active positions
; in each mode.
;
; Generally, these rules are true for any particular depth:
; #entries = (2^^depth)-1
; startposition = (256 / (2^^depth))-1
; skipfactor = 256 / (2^^depth)
SonoraCLUTTbl
DC.B $01,$7F,$00,$80 ; for one-bit mode
DC.B $03,$3F,$00,$40 ; for two-bit mode
DC.B $0F,$0F,$00,$10 ; for four-bit mode
DC.B $FF,$00,$00,$01 ; for eight-bit mode
DC.B $1F,$00,$00,$01 ; for sixteen-bit mode
SonoraCLUTRec RECORD 0 ;
scRange DS.B 1 ; maximum index value in this depth
scStart DS.B 1 ; lowest active CLUT address
scSkip DS.W 1 ; skip value between active addresses
SonoraCLUTSize Equ *
ENDR
;
; These are the bit patterns for grays in each depth
;
SonoraPats Dc.l OneBitGray,TwoBitGray,FourBitGray,EightBitGray,SixteenBitGray
;
; The following table is used by the SwitchMode call to determine two things. First,
; it must decide whether the requested mode to switch to is valid or not. If
; the requested mode is not in the SwitchTable, the call will fail. Also, even
; if the requested mode is in table, if the current bit depth is too large
; for the requested mode, SwitchMode must still fail.
;
SwitchTable
Dc.b sRsrc_Vid_Sonora_GSM, FifthVidMode
Dc.b sRsrc_Vid_Sonora_MSB1, FifthVidMode
Dc.b sRsrc_Vid_Sonora_MSB2, FourthVidMode
Dc.w -1
;
; The following tables are used to support the Get/SetAltSense codes. The first set of
; tables are pairs of codes and indices, terminated by a -1. Each of these tables
; is composed of a particular sense-code types (i.e., 3, 5, 6, and 7). The final
; table is also composed of pairs -- the first value is the sense-code type, and
; the corresponding second value is an offset to the sense-code index tables.
;
Type_0_MonIDs
Dc.b indexedSenseFP, indexedSenseFP
Dc.b indexedSenseRubik, indexedSenseRubik
Dc.b indexedSenseRGBFP, indexedSenseRGBFP
Dc.b indexedSenseHR, indexedSenseHR
Dc.b indexedNoConnect, indexedNoConnect
Dc.w -1
Type_6_MonIDs
Dc.b extendedMSB1, indexedSenseMSB1
Dc.b extendedMSB2, indexedSenseMSB2
Dc.b extendedMSB3, indexedSenseMSB3
Dc.w -1
Type_7_MonIDs
Dc.b extendedSenseVGA, indexedSenseVGA
Dc.b extendedSenseGF, indexedSenseGF
Dc.b extendedNoConnect, indexedNoConnect
Dc.w -1
MonIDsTbl Dc.w 0, Type_0_MonIDs-MonIDsTbl
Dc.w 3, 0
Dc.w 5, 0
Dc.w 6, Type_6_MonIDs-MonIDsTbl
Dc.w 7, Type_7_MonIDs-MonIDsTbl
Dc.w -1
;
; Unlike the SwitchTable above, the DepthTable tells SetDefaultMode what to write in the SP_Depth
; field of sPRAM. If the depth value is zero, SetDefaultMode is just supposed to leave
; the SP_Depth field alone. If the depth values is negative one, then SetDefaultMode is
; supposed to check to see if the current mode is valid or not.
;
DepthTable
Dc.b sRsrc_Vid_Sonora_FP, FirstVidMode
Dc.b sRsrc_Vid_Sonora_FPc, FourthVidMode
Dc.b sRsrc_Vid_Sonora_GS, FirstVidMode
Dc.b sRsrc_Vid_Sonora_GSa, FourthVidMode
Dc.b sRsrc_Vid_Sonora_GSb, FifthVidMode
Dc.b sRsrc_Vid_Sonora_GSM, 0
Dc.b sRsrc_Vid_Sonora_RGBFP, FirstVidMode
Dc.b sRsrc_Vid_Sonora_RGBFPc, FourthVidMode
Dc.b sRsrc_Vid_Sonora_HR, FirstVidMode
Dc.b sRsrc_Vid_Sonora_HRb, FourthVidMode
Dc.b sRsrc_Vid_Sonora_HRc, FifthVidMode
Dc.b sRsrc_Vid_Sonora_MSB1, 0
Dc.b sRsrc_Vid_Sonora_VGA, FirstVidMode
Dc.b sRsrc_Vid_Sonora_VGAb, FourthVidMode
Dc.b sRsrc_Vid_Sonora_VGAc, FifthVidMode
Dc.b sRsrc_Vid_Sonora_GF, FirstVidMode
Dc.b sRsrc_Vid_Sonora_GFb, FourthVidMode
Dc.b sRsrc_Vid_Sonora_MSB2, -1
Dc.w -1
**********************************************************************
*
* VidOpen allocates private storage for the device in the AuxDCE and locks
* it down for perpetuity. Also, it installs the interrupt handler and enables
* the (VBL) interrupts.
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
*
* Locals: A3 = pointer to private storage
*
* A4/D2/D3 used as scratch
*
**********************************************************************
WITH VDPageInfo,SlotIntQElement,SonoraVidPrivates
SonoraVidOpen
;
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
; a pointer to it in A3
;
MOVEQ #SonoraVidPrivSize,D0 ; get size of parameters
_ResrvMem ,SYS ; make room as low as possible
MOVEQ #SonoraVidPrivSize,D0 ; get size of parameters
_NewHandle ,SYS,CLEAR ; get some memory for private storage
BNE @OpError1 ; => return an error in open
MOVE.L A0,dCtlStorage(A1) ; save returned handle in AuxDCE
_HLock ; and lock it down forever
MOVE.L (A0),D0 ; get a pointer to it
_StripAddress ; clean it up
MOVE.L D0,A3 ; get pointer to privates in A3
;
; Remember the VDAC, Sonora, and framebuffer base addresses since they're non-trivial to
; look up.
;
WITH ProductInfo,DecoderInfo,VideoInfo
MOVE.L UnivInfoPtr,A0 ; get a pointer to universal data
ADDA.L DecoderInfoPtr(A0),A0 ; point to the base address table
MOVE.L VDACAddr(A0),saveVDACBase(A3) ; save VDACÕs base address
Move.l VIA1Addr(A0),saveSonoraBase(A3) ; save SonoraÕs base address (same as VIA1)<H5>
MOVE.L UnivInfoPtr,A0
ADDA.L VideoInfoPtr(A0),A0 ; point to the VideoInfo record
MOVE.L VRAMLogAddr32(A0),saveBaseAddr(A3) ; save base address too
ENDWITH
;
; Get and install the interrupt handler. Call the EnableVGuts utility code to do
; this. This utility also starts the interrupts going. If there is an error
; condition, EnableVGuts returns with the Z-bit cleared.
MOVEQ #sqHDSize,D0 ; allocate a slot queue element
_NewPtr ,SYS,CLEAR ; get it from system heap cleared
BNE @OpError2 ; if not allocated, return bad
MOVE.L A0,saveSQElPtr(A3) ; save the SQ element pointer.
; If the video driver was closed, letÕs ensure that video is unblanked before we
; re-enable interrupts.
;
Movea.l saveSonoraBase(A3),A0 ; Get the Sonora base address.
Adda.l #SonoraVdCtlBase,A0 ; Point to the video control register space.
Bclr #SonoraVidBlnkBit,SonoraVdModeReg(A0) ; Turn off video blanking.
BSR SonoraEnableVGuts ; do it
BNE @OpError2 ;
;
; Load the default gamma table from the slot resource list.
;
WITH SpBlock
SUBA #spBlockSize,SP ; make a slot parameter block
MOVE.L SP,A0 ; get pointer to block in A0
MOVE.B dCtlSlot(A1),spSlot(A0) ; copy the slot number
MOVE.B dCtlSlotId(A1),spID(A0) ; copy the spID of the video sRsrc
CLR.B spExtDev(A0) ;
_sRsrcInfo ; get the spsPointer
BNE @OpError3 ; if failed, then quit.
MOVE.B #sGammaDir,spID(A0) ; look for the gamma directory
_sFindStruct ; get that baby
BNE.S @DoLinear ; if failed, then do linear
MOVE.B #128,spID(A0) ; get the default gamma table, (always 128)
_sGetBlock ; we can use this since we want it on the sys heap
BNE.S @DoLinear ; if failed, then do linear
; Skip over gamma header.
MOVE.L spResult(A0),A0 ; point to head of the block
MOVE.L A0,saveGamDispPtr(A3) ; save the ptr to the gamma block
ADDA #2,A0 ; skip resID
@Name TST.B (A0)+ ; skip over gamma name
BNE.S @Name ;
MOVE.L A0,D0 ; get in d-reg
ADDQ #1,D0 ; word align pointer
BCLR #0,D0 ; round it off
MOVE.L D0,saveGammaPtr(A3) ; put it in private storage
Bra.s @VidParams ; Jump around linear code.
;
; Build a linear default gamma table if necessary.
;
@DoLinear
Moveq #gFormulaData,D0 ; Get gamma table header size.
Add #256,D0 ; Add in one-byte per entry.
_NewPtr ,SYS,CLEAR ; Clear it.
Bne @OpError3 ; If failed, quit.
Move.l A0,saveGamDispPtr(A3) ; Save head of gamma table for disposal.
Move.l A0,saveGammaPtr(A3) ; Head and top are same here.
Move.w #drHwSonora,gType(A0) ; Set up gType.
Move.w #1,gChanCnt(A0) ; Set up gChanCnt.
Move.w #256,gDataCnt(A0) ; Set up gDataCnt.
Move.w #8,gDataWidth(A0) ; Set up gDataWidth.
Adda #gFormulaData+256,A0 ; Point to end of data table.
Move.w #255,D0 ; Set up loop counter.
@Loop Move.b D0,-(A0) ; Write out value.
Dbra D0,@Loop ; Loop.
;
; Get a pointer to the video hardware setup parameter block. Use this functional spID's spsPointer
; found above in the gamma section.
;
@VidParams
Move.l Sp,A0 ; Point to the spBlock on the stack.
Clr.w spID(A0) ; Start looking at spID 0, no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Bne @OpError4 ; If failed, quit.
MOVE.B #sVidParmDir,spID(A0) ; look for the video parameters dir
_sFindStruct ; Try to load it.
Bne.s @OpError4 ; If failed, quit.
MOVE.B dCtlSlotId(A1),spID(A0) ; look in the directory for this config's parameters
_sGetBlock ; Try to load it.
Bne.s @OpError4 ; If failed, quit.
MOVE.L spResult(A0),saveVidPtr(A3) ; get pointer to it
;
; At PrimaryInit time, we used the sense lines to determine the type of attached display. For extended
; sense displays, we just mapped them to the end of indexed-sense displays. Since the gamma-correction
; code uses the monitor ID to determine if the passed-in table is applicable, we need to know the ÒrealÓ
; monitor ID. At PrimaryInit time, we store the real monitor ID in slot pRAM. So, we extract that
; information out here. Also, it should be noted that it would actually be inappropriate for us
; to re-read the sense-lines now, in that someone could potentially change/unplug the attached
; display between PrimaryInit and VidOpen, and that would cause us all sorts of havoc.
;
With SP_Params
Move.l Sp,A0 ; Point to spBlock on the stack.
Move.b dCtlSlot(A1),spSlot(A0) ; Put slot into spBlock.
Suba #sizeSPRamRec,Sp ; Allocate an SPRam block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_SReadPRAMRec ; Read Slot PRam.
Bne.s @OpError5 ; If failed quit.
Moveq #0,D2 ; Clear D2.w.
Move.b SP_MonID(Sp),D2 ; Get the monID (itÕs byte sized).
Move.b SP_Flags(Sp),D1 ; Get the flags.
Adda #sizeSPRamRec+spBlockSize,Sp ; Clean up the stack.
EndWith
;
; Do a little bookkeepingÉ
;
Move.w D2,saveMonID(A3) ; Save the monID for later.
Btst #spNoVRAM,D1 ; Test for real VRAM or not.
Sne noVRAM(A3) ; Remeber it for later.
Bfextu D1{spVRamBits:numSPVRamBits},D1 ; Extract the vRAM/RAM size from the flags byteÉ
Move.b D1,saveSizeVRAM(A3) ; É and save it for later.
;
; Set GFlags to reflect monochrome-only displays.
;
Cmp.w #indexedSenseFP,saveMonID(A3) ; If this is a Mono-Only Full Page,
Beq.s @SetMonoFlags ; then say so.
Bra.s @ChkRubik560 ; Otherwise, skip.
@SetMonoFlags Bset #IsMono,GFlags(A3) ; Turn on the IsMono and
Bset #GrayFlag,GFlags(A3) ; GrayFlag flags.
;
; Set GFlags to reflect whether we started up in Rubik-560 mode or not.
;
@ChkRubik560
Cmp.b #sRsrc_Vid_Sonora_GS560a,dCtlSlotId(A1) ; If weÕre in Rubik-560a mode,
Beq.s @SetRubik560 ; then say so.
Cmp.b #sRsrc_Vid_Sonora_GS560b,dCtlSlotId(A1) ; If weÕre not in Rubik-560b mode,
Bne.s @AllDone ; then just go on.
@SetRubik560 Bset #InRubik560Mode,GFlags(A3) ; Remember that we started up in Rubik-560 mode.
;
; All done!
;
@AllDone MOVEQ #noErr,D0 ; no error
@EndOpen RTS ; return
@OpError5 Adda #sizeSPRamRec,Sp ; Release the SPRam block.
@OpError4 Move.l saveGamDispPtr(A3),A0 ; Set up to dispose of gamma table.
_DisposPtr ; Dispose it.
@OpError3 ADDA #spBlockSize,SP ; release the spBlock
@OpError2 MOVE.L dCtlStorage(A1),A0 ; get the private storage back
_DisposHandle ; release the driver private storage
@OpError1 MOVE.L #OpenErr,D0 ; say can't open driver
BRA.S @EndOpen
ENDWITH
**********************************************************************
*
* Video Driver Control Call Handler. There are 11 standard calls:
*
* ($00) Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr);
* ($01) KillIO
* ($02) SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr);
* ($03) SetEntries (Table: Ptr; Start,Count : integer );
* ($04) SetGamma (Table : Ptr );
* ($05) GrayPage (page);
* ($06) SetGray (csMode = 0 for color, 1 for gray)
* ($07) SetInterrupt (csMode = 0 for enable, non-zero for disable);
* ($08) DirectSetEntries (Table: Ptr; Start,Count : integer );
* ($09) SetDefaultMode (csMode = mode to set);
* ($0A) SwitchMode(csMode, csData, csPage, csBaseAddr);
*
* The following calls are Sonora-specific:
*
* ($81) SetRubik560Mode (csMode = 0 for enable, non-zero for disable);
* ($83) SetAltSense(csMode = byte 0 is sense code, byte 1 is type);
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
* Uses: A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved)
* A3 = ptr to our privates/scrarch (doesnÕt need to be preserved)
* A4 = scratch (must be preserved)
* D0-D3 = scratch (don't need to be preserved)
*
* Exit: D0 = error code
*
**********************************************************************
;
; Decode the callÉ
;
SonoraVidCtl
MOVEM.L A0/A1,-(SP) ; Save exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
Cmp.w #cscRubik560,D0 ; If we got the Rubik560 mode call,
Beq SonoraSetRubik560Mode ; hop to it.
Cmp.w #cscAltSense,D0 ; If we got the alternate senseID call,
Beq SonoraSetAltSense ; hop to it.
CMP.W #$0B,D0 ; IF csCode NOT IN [0..$0A] THEN ; <sm20>
BHI.S SonoraCtlBad ; Error, csCode out of bounds.
MOVE.W SonoraCtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine.
JMP SonoraCtlJumpTbl(PC,D0.W) ; GOTO the proper routine.
SonoraCtlJumpTbl
DC.W SonoraVidReset-SonoraCtlJumpTbl ; $00 => VidReset
DC.W SonoraCtlGood-SonoraCtlJumpTbl ; $01 => CtlGood (no async routines here)
DC.W SonoraSetVidMode-SonoraCtlJumpTbl ; $02 => SetVidMode
DC.W SonoraSetEntries-SonoraCtlJumpTbl ; $03 => SetEntries
DC.W SonoraSetGamma-SonoraCtlJumpTbl ; $04 => SetGamma
DC.W SonoraGrayPage-SonoraCtlJumpTbl ; $05 => GrayPage
DC.W SonoraSetGray-SonoraCtlJumpTbl ; $06 => SetGray
DC.W SonoraSetInterrupt-SonoraCtlJumpTbl ; $07 => SetInterrupt
DC.W SonoraDirectSetEntries-SonoraCtlJumpTbl ; $08 => DirectSetEntries
DC.W SonoraSetDefaultMode-SonoraCtlJumpTbl ; $09 => SetDefaultMode
DC.W SonoraSwitchMode-SonoraCtlJumpTbl ; $0A => SwitchMode
DC.W SonoraSetSync-SonoraCtlJumpTbl ; $0B => SetSync ; <sm20>
SonoraCtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
BRA.S SonoraCtlDone ; and return
SonoraCtlGood MOVEQ #noErr,D0 ; return no error
SonoraCtlDone MOVEM.L (SP)+,A0/A1 ; Restore Exit registers.
BRA SonoraExitDrvr
SonoraVidReset
;---------------------------------------------------------------------
;
; Reset the card to its default
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVE #FirstVidMode,csMode(A2) ; return default mode
MOVE #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
MOVEQ #0,D1 ; get default depth in D1 (#firstVidMode-#firstVidMode)
MOVEQ #0,D0 ; get page in D0
MOVE D0,csPage(A2) ; return the page
BSR SonoraSetDepth ; set the depth from D1
BCLR #IsDirect,GFlags(A3) ; turn off direct mode bit
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
BSR SonoraGrayScreen ; paint the screen gray
BRA.S SonoraCtlGood ; => no error
ENDWITH
SonoraSetVidMode
;---------------------------------------------------------------------
;
; Set the card to the specified mode. Only page zero is possible,
; so we need to check that the request was OK.
;
; If the card is already set to the specified mode, then do nothing.
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVE.W csMode(A2),D1 ; D1 = mode
BSR SonoraChkMode ; check mode and convert
BNE.S SonoraCtlBad ; => not a valid mode
TST.W csPage(A2) ; only page zero is valid
BNE.S SonoraCtlBad ; => not a valid page
; Only set if mode has changed.
SonoraSetVidModeGuts
MOVE.W csMode(A2),D2 ; get the mode spID (D1 has the zero-based mode)
CMP saveMode(A3),D2 ; has the mode changed?
BEQ @ModeOK1 ; if not, then skip graying
; Remember the newly requested mode.
MOVE.W D2,saveMode(A3) ; remember requested mode
; Set the entire color table to gray before switching to avoid screen anomalies.
Movem.l A4-A6,-(Sp) ; Save gamma-table registers.
Move.l saveGammaPtr(A3),A0 ; Get pointer to gamma data structure.
Lea gFormulaData(A0),A4 ; Point to first gamma table.
Adda.w gFormulaSize(A0),A4 ;
Move.l A4,A5 ; Point to green data (assuming gChanCnt = 1).
Move.l A4,A6 ; Point to red data (assuming gChanCnt = 1).
Cmp.w #1,gChanCnt(A0) ; If thereÕs only one table,
Beq.s @OnlyOneTable ; then weÕre set.
Move.w gDataWidth(A0),D2 ; Get width of each entry (in bits).
Move.w gDataCnt(A0),D0 ; Get # of entries in table.
Addq #7,D2 ; Round to nearest byte.
Lsr.w #3,D2 ; Get bytes per entry.
Mulu D2,D0 ; Get size of table in bytes.
Adda.w D0,A5 ; Calc base of green (red base + D0).
Adda.w D0,A6 ; Calc baseÉ
Adda.w D0,A6 ; Éof blue (red base + D0 + D0).
@OnlyOneTable
Move.w gDataCnt(A0),D3 ; Save number of gamma entries.
MOVE.L saveVDACBase(A3),A0 ; get the VDAC base addr
ADDA #ArielDataReg,A0 ; point to data register
CLR.B ArielAddrReg-ArielDataReg(A0) ; start at the beginning of CLUT
MOVE.W SR,-(SP) ; preserve the status register
BSR SonoraWaitVSync ; wait for next blanking period (preserves A0)
; Write out gamma-corrected true-gray CLUTÉ
;
Move.w D3,D0 ; Init loop counter.
Subq #1,D0 ; Zero base it.
Move.w GFlags(A3),D2 ; Get the GFlags into a convenient register.
Lsr.w #1,D3 ; Get midpoint of table(s).
@Repeat Btst #IsMono,D2 ; If this is not a mono-only display
Beq.s @DoRGB ; then do the standard RGB stuff.
Clr.b (A0) ; Otherwise, just write black out
Clr.b (A0) ; to the red & green channels.
Bra.s @DoMono ;
@DoRGB Move.b (A4,D3),(A0) ; Write: red,
Move.b (A5,D3),(A0) ; green,
@DoMono Move.b (A6,D3),(A0) ; blue.
Dbra D0,@Repeat
MOVE (SP)+,SR ; restore the status reg
Movem.l (Sp)+,A4-A6 ; Restore gamma-table registers.
BSR SonoraSetDepth ; set the depth from D1
; Finish up the bookkeeping.
CMP.W #FifthVidMode,saveMode(A3) ; was it a direct mode?
BLT.S @BitOff ; no, so turn flag off
BSET #IsDirect,GFlags(A3) ; turn on bit
BRA.S @ModeOK1 ;
@BitOff
BCLR #IsDirect,GFlags(A3) ; turn off bit
@ModeOK1 Move.l saveBaseAddr(A3),csBaseAddr(A2) ; return the base addr
BRA SonoraCtlGood ; return no error
ENDWITH
SonoraSetEntries
;---------------------------------------------------------------------
;
; Input :
; csParam -> datablock
; datablock = csTable -> table of colorSpecs (not colortable)
; csStart -> where to start setting, or -1
; csCount -> # of entries to change
;
; This call has two modes. In SEQUENCE mode, csCount entries are changed
; in the CLUT, starting at csStart. In INDEX mode, csCount entries are
; installed into the CLUT at the positions specified by their .value fields.
; This mode is selected by passing csStart = -1. In both cases, entries are
; range-checked to the dynamic range of the video mode (bits/pixel).
;
;---------------------------------------------------------------------
;
; Set the CLUT
; A0 = Ptr to the table
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private data, later to CLUT constants table
; A4 = Ptr to gamma red table
; A5 = Ptr to gamma green table
; A6 = Ptr to gamma blue table
;
; D0-D3 = Scratch
; D4 = Size of stack color table buffer
; D5 = GFlags word
; D6 = Index range [0..n]
; D7 = gamma channel size in bits
;
;---------------------------------------------------------------------
; Initialize loop.
WITH SonoraVidPrivates,SonoraCLUTRec
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BNE SonoraCtlBad ; error if so
SonoraSEGuts
TST.L csTable(A2) ; Check for a nil pointer
BEQ SonoraCtlBad ;
MOVEM.L A1/A4-A6/D4-D7,-(SP) ; save registers for gamma
MOVE.W GFlags(A3),D5 ; get GFlags word in D5
CMP.W #indexEntries,csStart(A2) ; was it indexed mode?
BEQ.S @SkipSeq ; if so, then leave bit off (it's never turned on in GFlags)
Bset #PsuedoIndex,D5 ; turn on the bit that denotes a seq write that was xlated to indexed
Cmp.w #FourthVidMode,saveMode(A3) ; If itÕs not 8bbp or 16bpp,
Blt.s @SkipSeq ; need to use ÒindexedÓ.
BSET #UseSeq,D5 ; otherwise, turn on sequential mode bit
@SkipSeq
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
MOVE.W gFormulaSize(A0),D0 ; get the size of formula data
LEA gFormulaData(A0,D0),A4 ; red correction table starts here
MOVE.L A4,A5 ; get default pointer to green data
MOVE.L A4,A6 ; get default pointer to blue data
MOVE gDataWidth(A0),D7 ; get width of each entry in bits
CMP #1,gChanCnt(A0) ; if only only one table, we're set
BEQ.S @OneTbl ; => just one table
MOVE gDataCnt(A0),D0 ; get # entries in table
MOVE D7,D1 ; copy it to goof around
ADDQ #7,D1 ; round to nearest byte
LSR #3,D1 ; get bytes per entry
MULU D1,D0 ; get size of table in bytes
ADDA D0,A5 ; calc base of green
ADDA D0,A6 ; calc base of blue
ADDA D0,A6 ; calc base of blue
@OneTbl
;
; Get the maximum number of entries, zero based from a convenient table.
;
MOVE.W saveMode(A3),D1 ; get the current video mode
SUB.W #FirstVidMode,D1 ; convert to a index
Moveq #0,D4 ; clear all of D4 for .w compare.
Lea SonoraCLUTTbl,A0 ; Point to the table of CLUT data.
Lea (A0,D1*SonoraCLUTSize),A0 ; Point to the right entry.
Move.b scRange(A0),D4 ; Get the range.
;
; Allocate a temporary color table on the stack. We'll pre-process all the entries that will
; change here so we can hit the hardware as quickly as possible.
;
Move.w csCount(A2),D3 ; Get the number of entries to change,
Bmi SonoraSEBadExit ; and hike if itÕs out of range.
Cmp.w D4,D3 ; If D3-D4 > 0 (count - range > 0),
Bhi SonoraSEBadExit ; then hike.
Tst.w csStart(A2) ; If weÕre doing indexed entries (-1),
Bmi.s @skipStartChk ; then just go on.
Add.w csStart(A2),D3 ; Adjust count for starting position.
Cmp.w D4,D3 ; If D3-D4 > 0 (count - range > 0),
Bhi SonoraSEBadExit ; then hike.
Move.w csCount(A2),D3 ; Otherwise, re-get the count.
@skipStartChk
Move.w D3,D4 ; Make a copy of the table size (zero-based).
Addq #1,D4 ; Make it a counting number.
Btst #UseSeq,D5 ; If weÕre not in sequential mode,
Beq.s @IsIndex ; then do the indexed stuff.
Mulu #3,D4 ; Make room for just R,G,B in sequential mode.
Bra.s @AllocIt ; And continue.
@IsIndex Asl.w #2,D4 ; Make room for i,R,G,B in indexed mode.
@AllocIt Sub.w D4,Sp ; Allocate the table on the stack.
;
; Construct the stack version of the color table. It looks like a color table, but each of the
; components is only eight bits (rather than 16).
;
Move.l A3,D6 ; WeÕre about to torch A3, so save it for later.
Move.l A0,A3 ; Save the CLUT table entry pointer.
MOVE.L SP,A0 ; copy the stack buffer pointer
MOVE.L csTable(A2),A1 ; get colorSpec pointer into A1
; Death! Totally out of registers in this routine, so I'm using the top half of D4 (the temp buffer
; size) as the sequence counter used in most video modes to translate sequential requests into
; the indexed write that the hardware needs.
SWAP D4 ; flip the buffer size to the top half
MOVE.W csStart(A2),D4 ; pick up the sequential start position. It might
; be -1 on a true indexed write, but we won't
; use it below if it is.
;
; Write the index if in indexed mode. If in sequential (8/16) mode, blow it off completely,
; since it won't be needed.
@SetupLoop
MOVE.W (A1)+,D0 ; get index
BTST #UseSeq,D5 ; is it sequence mode?
BNE.S @SLSeq ; yup, so go there
Btst #PsuedoIndex,D5 ; If we are doing an ÒindexedÓ mode,
Beq.s @IndexPresent ; then go there now.
; This case is a sequential request in a screen depth that does not allow sequential CLUT writes
; (any non-8/16 bit mode). In this case, we substitute the sequence counter for D0 on each
; entry.
Move.w D4,D0 ; Copy the sequence counter to D0.
Addq #1,D4 ; Increment it.
@IndexPresent Mulu.w scSkip(A3),D0 ; Calculate the new position at this depth.
Add.b scStart(A3),D0 ; Add in the first entry offset.
Move.b D0,(A0)+ ; Write out this index.
@SLSeq
MOVE.W (A1)+,D0 ; get red
MOVE.W (A1)+,D1 ; get green
MOVE.W (A1)+,D2 ; get blue
TST D5 ; test hi bit of the flags
BPL.S @NoGray ; if not set, don't luminence map
BTST #IsDirect,D5 ; test for direct mode as well
BNE.S @NoGray ; don't allow luminence mapping in direct mode
; We're luminence mapping here.
MULU #$4CCC,D0 ; multiply by red weight (0.30)
MULU #$970A,D1 ; multiply by green weight (0.59)
MULU #$1C29,D2 ; multiply by blue weight (0.11)
ADD.L D1,D0 ; sum red and green
ADD.L D2,D0 ; blue also
BFEXTU D0{0:D7},D0 ; get gChanWidth bits for gamma table lookup
MOVE.W D0,D1 ; copy into green register
MOVE.W D0,D2 ; copy into blue register
BRA.S @WriteSP ; go on and write it in the stack buffer
@NoGray
BFEXTU D0{16:D7},D0 ; get gChanWidth bits of red
BFEXTU D1{16:D7},D1 ; get gChanWidth bits of green
BFEXTU D2{16:D7},D2 ; get gChanWidth bits of blue
@WriteSP
BTST #IsMono,D5 ; if monochrome display, write black to red & green
BEQ.S @Brighter ; if not, then set all three channels
CLR.B (A0)+ ; write black for red
CLR.B (A0)+ ; and green
BRA.S @Looper ; write out normal blue
@Brighter
MOVE.B (A4,D0),(A0)+ ; write gamma corrected red
MOVE.B (A5,D1),(A0)+ ; write gamma corrected green
@Looper
MOVE.B (A6,D2),(A0)+ ; write gamma corrected blue
DBRA D3,@SetupLoop ; and loop for each entry
Swap D4 ; Put the temp buffer size back in the lo-half.
;
; OK, the stack table is set up. Now let's load the hardware.
;
Move.l D6,A3 ; Get our privates pointer back into A3 (for WaitVSync).
Move.w Sr,-(SP) ; Preserve the status register.
BSR SonoraWaitVSync ; Wait for next blanking period (preserves A0/D0).
MOVE.W csCount(A2),D3 ; get the count again
MOVE.L saveVDACBase(A3),A3 ; get the VDAC base
LEA ArielDataReg(A3),A3 ; point to VDAC data register
LEA 2(SP),A0 ; point to the stack buffer again
BTST #UseSeq,D5 ; is it sequence mode?
BNE.S SonoraSeqWrite ; yup, sequence mode, so go there
;
; Here's the loop that actually writes to the hardware when in indexed mode.
;
SonoraIndexWrite
MOVE.B (A0)+,ArielAddrReg-ArielDataReg(A3) ; write the index value to the CLUT address
MOVE.B (A0)+,(A3) ; write red
MOVE.B (A0)+,(A3) ; write green
MOVE.B (A0)+,(A3) ; write blue
DBRA D3,SonoraIndexWrite ; and loop
BRA.S SonoraSEDone ;
;
; Write the translated starting position for sequence mode.
;
SonoraSeqWrite
MOVE.W csStart(A2),D0 ; get sequence start address
MOVE.B D0,ArielAddrReg-ArielDataReg(A3) ; write the sequence start position
;
; Here's the loop that actually writes to the hardware when in sequence mode.
;
@SeqLoop
MOVE.B (A0)+,(A3) ; write red
MOVE.B (A0)+,(A3) ; write green
MOVE.B (A0)+,(A3) ; write blue
DBRA D3,@SeqLoop ; and loop
;
; Clean up and go home.
;
SonoraSEDone
MOVE.W (SP)+,SR ; restore status register
ADD.W D4,SP ; release stack buffer
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA SonoraCtlGood ; return O-Tay!
SonoraSEBadExit
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA SonoraCtlBad ; return an error code
ENDWITH
SonoraSetGamma
;---------------------------------------------------------------------
;
; Set the gamma table. This call copies the supplied gTable so the
; caller does not have to put the source on the system heap. It
; tests if the gamma table is exactly a match to the currently
; connected monitor, or always allows it if the monitor number in
; the FormulaData is -1. If supplied gamma table ptr is NIL, then
; it loads a linear gamma table into the private table
;
; A0 = Ptr to private storage
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
; Get new gamma table and check that we know how to handle it.
MOVE.L csGTable(A2),D0 ; test for a NIL pointer
BEQ @LinearTab ; if so, then set up a linear gamma table
MOVE.L D0,A2 ; get pointer to new gamma table
TST.W gVersion(A2) ; version = 0?
BNE SonoraCtlBad ; => no, return error
Tst.w gType(A2) ; Test the hardwareID.
Beq.s @ChangeTable ; If 0, then accept a TFB-style gamma table.
CMP.W #drHwSonora,gType(A2) ; type = Sonora?
BNE SonoraCtlBad ; => no, return error
TST.W gFormulaSize(A2) ; if gType=Sonora, then check for monID in gFormulaData
BEQ.S @ChangeTable ; if zero, then generic, so continue
MOVE.W gFormulaData(A2),D0 ; get the monitor ID this table was intended for
CMP.W saveMonID(A3),D0 ; is this the monitor?
BEQ.S @ChangeTable ; yes, so do it
ADDQ #1,D0 ; was it -1?
BNE SonoraCtlBad ; nope, so must be wrong monitor
; If new table is a different size, reallocate memory.
@ChangeTable
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0
MOVE gFormulaSize(A2),D0 ; get size of formula in new
CMP gFormulaSize(A0),D0 ; same as current gamma table
BNE.S @GetNew ; =>no, resize pointer
MOVE gChanCnt(A2),D0 ; get number of tables in new
CMP gChanCnt(A0),D0 ; same as current gamma table?
BEQ.S @SizeOK ; => yes, data size ok
BGT.S @GetNew ; => new one is bigger, save old one
@NewSize Move.l saveGamDispPtr(A3),A0 ; if new one is smaller,
_DisposPtr ; dispose old one
CLR.L saveGamDispPtr(A3) ; flag it's been disposed
@GetNew Moveq #0,D0 ; (_NewPtr takes a long, so clear D0 for later.)
MOVE gDataCnt(A2),D0 ; get number of entries
MULU gChanCnt(A2),D0 ; multiply by number of tables
ADD gFormulaSize(A2),D0 ; add size of formula data
ADD #gFormulaData,D0 ; add gamma table header size
_NewPtr ,Sys ; and allocate a new pointer
BNE SonoraCtlBad ; => unable to allocate storage
MOVE.L saveGamDispPtr(A3),D0 ; get old gamma table
MOVE.L A0,saveGammaPtr(A3) ; save new gamma table
TST.L D0 ; was there an old one?
BEQ.S @SizeOK ; => no, already disposed
MOVE.L D0,A0 ; else get old table
_DisposPtr ; and dispose of old gamma table
MOVE.L saveGammaPtr(A3),A0 ; get new gamma table back
Move.l A0,saveGamDispPtr(A3) ; save it for disposal
; Copy the gamma table header.
@SizeOK MOVE gChanCnt(A2),D0 ; get number of tables
MOVE gFormulaSize(A2),D1 ; get size of formula data
MOVE gDataCnt(A2),D2 ; get number of entries
MOVE.L (A2)+,(A0)+ ; copy gamma header
MOVE.L (A2)+,(A0)+ ; which is
MOVE.L (A2)+,(A0)+ ; 12 bytes long
; Copy the data.
MULU D0,D2 ; multiply by number of tables
ADD D1,D2 ; add in size of formula data
SUBQ #1,D2 ; get count - 1
@NxtByte MOVE.B (A2)+,D0 ; get a byte
MOVE.B D0,(A0)+ ; move a byte
DBRA D2,@NxtByte ; => repeat for all bytes
Bra.s @GammaDone ; Check to see if itÕs a direct device.
;
; Set up a linear gamma table. To prevent memory thrash, build this new one
; the same size as the existing one (one or three channel).
;
@LinearTab
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0
MOVE.W gFormulaSize(A0),D0 ; get size of formula in new
MOVE.W gChanCnt(A0),D2 ; get the number of tables
SUBQ #1,D2 ; zero based, of course
Move.w gDataCnt(A0),D3 ; get the number of entries
Subq #1,D3 ; zero base
ADDA #gFormulaData,A0 ; point to tables
ADDA D0,A0 ; point past monID, if present
@ChanLoop MOVE.W D3,D0 ; loop count within each channel
@entryLoop MOVE.B D0,(A0) ; write this value out
Not.b (A0)+ ; invert to make table ramp properly
DBRA D0,@entryLoop ; for each entry in channel
DBRA D2,@ChanLoop ; and each channel
@GammaDone
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ.S @Out ; if not, then we're done
BSR SonoraDirectCLUTSet ; if so, then set up direct CLUT ramps
@Out
BRA SonoraCtlGood ; => return no error
ENDWITH
SonoraGrayPage
;---------------------------------------------------------------------
;
; Clear the specified page in the current mode to gray
;
; A0 = Ptr to private storage
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to driver privates
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVE saveMode(A3),D1 ; D1 = mode
BSR SonoraChkMode ; convert mode to depth in D1
BNE SonoraCtlBad ; => not a valid depth
MOVE csPage(A2),D0 ; D0 = page
BNE SonoraCtlBad ; => not a valid page
BSR SonoraGrayScreen ; paint the screen gray
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ.S @Out ; if not, then we're done
BSR SonoraDirectCLUTSet ; if so, then set up direct CLUT ramps
@Out
BRA SonoraCtlGood ; => return no error
ENDWITH
SonoraSetGray
;---------------------------------------------------------------------
;
; Set luminance mapping on (csMode = 1) or off (csMode = 0)
;
; When luminance mapping is on, RGB values passed to setEntries are mapped
; to grayscale equivalents before they are written to the CLUT.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
BTST #IsMono,GFlags(A3) ; is this a mono-only monitor?
BEQ.S @1 ; if not, then go ahead
MOVE.B #1,csMode(A2) ; always turn on for mono devices
@1 MOVEQ #0,D1 ; set up for BFEXTU to point to GrayFlag
BSR.S SonoraSetIntCom ; call common code
BRA SonoraCtlGood ; all done
;
; This shared routine setup up a flag in GFlags. It takes a pointer to
; private storage in A3, and the bit field start location in D1.
;
SonoraSetIntCom
MOVE.B csMode(A2),D0 ; get boolean
BFINS D0,GFlags(A3){D1:1} ; set flag bit
RTS ; and return
ENDWITH
SonoraSetInterrupt
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = 1) VBL interrupts
;
; As a future performance enhancement, interrupts on the card can be
; disabled or enabled from software. For instance, if the cursor is
; not on a screen, and there is nothing in the Slot Interrupt Queue
; for that device, interrupts may be disabled reducing interrupt
; overhead for the system.
;
; The slot interrupt queue element is always allocated by the Open call.
; This routine just inserts and removes it from the slot interrupt task queue.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH VDPageInfo,SlotIntQElement,SonoraVidPrivates
MOVEQ #1,D1 ; set up for BFEXTU to point to IntDisFlag
BSR.S SonoraSetIntCom ; call common code
BNE.S @DisableThem ; if zero, then enable
; This code enables interrupts and installs the interrupt handler.
;
BSR.S SonoraEnableVGuts ; call common code
BNE SonoraCtlBad ; error, flag problem
BRA SonoraCtlGood ; and go home
; This code disables VBL interrupts, then removes the interrupt handler.
;
@DisableThem
BSR.S SonoraDisableVGuts ; jump to the disabling utility
BRA SonoraCtlGood ; all done
; The following two routines are common code shared between the Open/Close calls
; and the SetInterrupt control call.
;
SonoraDisableVGuts
MOVE.W SR,-(SP) ; preserve the status register
BSR SonoraWaitVSync ; to be safe, wait for the next VBL
Move.l saveSonoraBase(A3),A0 ; Get the Sonora base address.
Adda.l #SonoraVIA2Base,A0 ; Point to the interrupt register space.
Move.b #$40,SonoraSlotIER(A0) ; Disable Slot $0 interrupts.
MOVE (SP)+,SR ; re-enable cursor interrupts
CLR D0 ; setup slot # for _SIntRemove (slot zero!)
MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer
_SIntRemove ; remove the interrupt handler
RTS
SonoraEnableVGuts
MOVE.L saveSQElPtr(A3),A0 ; get the queue element
LEA SonoraBeginIH,A2 ; save Pointer to interrupt handler
MOVE.W #SIQType,SQType(A0) ; setup queue ID
MOVE.L A2,SQAddr(A0) ; setup int routine address
MOVE.L A3,SQParm(A0) ; pass pointer to privates as the parameter
CLR.W D0 ; setup slot zero
_SIntInstall ; and do install
BNE.S @IntBad
Move.l A0,-(Sp) ; Save the queue element pointer.
Move.l saveSonoraBase(A3),A0 ; Get the Sonora base address.
Adda.l #SonoraVIA2Base,A0 ; Point to the interrupt register space.
Move.b #$C0,SonoraSlotIER(A0) ; Enable Slot $0 interrupts.
Move.l (Sp)+,A0 ; Restore the queue elemetn pointer.
CMP D0,D0 ; clear z-bit for good result
@IntBad RTS ; return home (if bad, z-bit is set above, so just leave) <8>
ENDWITH
SonoraDirectSetEntries
;---------------------------------------------------------------------
;
; Change the CLUT in a direct mode.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
; This routine allows knowledgeable programs modify the contents
; of the CLUT in direct modes (usually for limited color previewing).
; It takes the same parameter block as SetEntries, but SetEntries
; intentionally does not operate when the card is in a direct pixMode.
; This routine takes the same data and operates ONLY when in direct
; modes. It calls the same SetEntries guts as the regular routine.
;
;---------------------------------------------------------------------
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ SonoraCtlBad ; error if not
BRA SonoraSEGuts ; jump to SetEntries internals if it's OK
SonoraSetDefaultMode
;---------------------------------------------------------------------
;
; Write the card default mode into slot pRAM.
;
; A1 = Ptr to AuxDCE (but trashed on exit)
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
; This routine is called by Monitors when somebody selects an alternate
; video mode family in the Options dialog.
;
;---------------------------------------------------------------------
WITH spBlock,SonoraVidPrivates,SP_Params
;
; Set up a slot parameter block on the stack.
;
SUBA #spBlockSize,SP ; make an slot parameter block on stack
MOVE.L SP,A0 ; get pointer to parm block now
MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock
CLR.B spExtDev(A0) ; external device = 0
;
; Read the slot pRAM to determine what the currently saved mode is. The first
; word is the board ID, followed by the default screen depth. Built-in video keeps the video
; sRsrc spID in VendorUse2.
;
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
MOVE.L SP,spResult(A0) ; point to it
_sReadPRAMRec ; read it
;
; Since PrimaryInit relies on the default mode being set correctly, we check to see that
; the mode to be set is actually valid. Monitors can only see valid sRsrcIDs, so
; it probably wonÕt cause a problem. But we should check it anyway for unsavory
; applications.
;
Move.b csMode(A2),spID(A0) ; Look for the passed in spID.
Clr.l spParamData(A0) ; Clear the fNext flag; we want THIS sRsrc.
Ori.b #(1<<fall)|\ ; Search for both enabled/disabled sRsrcÕs
(1<<foneslot),spParamData+3(A0) ; Only search in our slot.
_GetsRsrc ; Do it.
Bne @BadExit ; If failed, quit.
Move.w spCategory(A0),D0 ; Get the category.
Cmp.w #catDisplay,D0 ; If itÕs not catDisplay,
Bne @BadExit ; then quit.
Move.w spCType(A0),D0 ; Get the type.
Cmp.w #typVideo,D0 ; If itÕs not typVideo,
Bne @BadExit ; then quit.
Move.w spDrvrSw(A0),D0 ; Get the software kind.
Cmp.w #drSwApple,D0 ; If itÕs not drSwApple,
Bne @BadExit ; then quit.
Move.w spDrvrHw(A0),D0 ; Get the hardware ID.
Cmp.w #drHwSonora,D0 ; If itÕs not drHwSonora,
Bne @BadExit ; then quit.
;
; It is very important that Monitors (or someone) invalidate and setup the screen resource
; if this call is exercised. Monitors needs to verify (and potentially re-write to pRAM)
; the proper screen depth in the new world.
;
Move.b csMode(A2),D1 ; Copy the desired family mode.
Cmp.b SP_LastConfig(Sp),D1 ; If weÕre already going to this mode,
Beq.s @GoodExit ; then just go on.
Movea.l A0,A1 ; Save the SpBlockPtr.
Tst.b noVRAM(A3) ; If we have real VRAM, then
Beq.s @WriteIt ; just go on.
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 not around,
Beq.s @NoDM ; then do the non-dynamic stuff.
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @WriteIt ; then skip the non-dynamic stuff.
Cmpi.w #indexedSenseMSB2,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @WriteIt ; then skip the non-dynamic stuff.
Cmpi.w #indexedSenseMSB3,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @WriteIt ; then skip the non-dynamic stuff.
@NoDM Bset #spFamilyChanged,SP_Flags(Sp) ; Say that weÕre changing the mode.
Lea DepthTable,A1 ; Point to table of depths.
@DepthLoop Move.b (A1)+,D0 ; Get the next sRsrcID.
Cmpi.b #-1,D0 ; If weÕre at the end of the table,
Beq.s @WriteIt ; then just go on.
Move.b (A1)+,D2 ; Save the depth.
Cmp.b D0,D1 ; Otherwise, if the sRsrcIDs donÕt match,
Bne.s @DepthLoop ; then keep looping.
Tst.b D2 ; If the depth byte is zero,
Beq.s @WriteIt ; then just leave things alone.
Cmpi.b #-1,D2 ; If the depth byte is negative one,
Beq.s @ChkDepth ; then check the current depth.
Move.b D2,SP_Depth(Sp) ; Otherwise, write it out.
Bra.s @WriteIt
@ChkDepth Cmpi.b #FifthVidMode,SP_Depth(Sp) ; If were not set for 16bpp mode,
Bne.s @WriteIt ; then just go on.
Move.b #FourthVidMode,SP_Depth(Sp) ; Otherwise, say we want 8bpp instead.
@WriteIt Movea.l A1,A0 ; Restore the SpBlockPtr.
MOVE.B D1,SP_LastConfig(SP) ; write the mode into pRAM buffer
MOVE.L SP,spsPointer(A0) ; set up parameter block
_sPutPRAMRec ; write the new record out
@GoodExit ADDA #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
BRA SonoraCtlGood ; return good result.
@BadExit Adda #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
Bra SonoraCtlBad ; return bad result.
ENDWITH
SonoraSwitchMode
;---------------------------------------------------------------------
;
; When driving a multiscan-capable display, this routine allows
; the various modes to swapped out both from a low-level software
; (i.e., Driver & Slot Manager) and hardware point of view.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With SonoraVidPrivates,SpBlock,VDPageInfo
; Check to see if we even need to be here or notÉ
;
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Cmpi.w #indexedSenseMSB2,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Cmpi.w #indexedSenseMSB3,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Bra SonoraCtlBad ; Otherwise, just go away.
@EndMSChk
; Check to see if we can even do what was requestedÉ
;
Tst.w csPage(A2) ; If requested page is not zero,
Bne.s SonoraCtlBad ; then we canÕt help Õem.
Move.l csData(A2),D2 ; Get the requested SpID.
Moveq #0,D0 ; Clear hi-half of mode/depth register.
Lea SwitchTable,A0 ; Point to the SwitchMode table.
@ChkLoop Move.b (A0)+,D1 ; Get the next sRsrcID.
Cmpi.b #-1,D1 ; If weÕre at the end of the table,
Beq SonoraCtlBad ; then somethingÕs wrong.
Move.b (A0)+,D0 ; Get the max mode for this config.
Cmp.b D1,D2 ; If this is not the requested mode,
Bne.s @ChkLoop ; then keep looping.
; Make sure the new depth is okay for switchingÉ
;
Move.w csMode(A2),D1 ; Get the requested mode (depth).
Subi.w #FirstVidMode,D1 ; Make it indexed.
Subi.w #FirstVidMode,D0 ; Make the new max mode indexed.
Cmp.w D0,D1 ; If the current mode is > new max mode,
Bgt SonoraCtlBad ; then punt.
Move.w D1,D0 ; Save the indexed mode.
; Switch to the new resolutionÉ
;
Cmp.b dCtlSlotID(A1),D2 ; If weÕre already in the requested resolution,
Beq SonoraSetVidModeGuts ; then go try the depth switch.
Move.b D2,D1 ; Set up to do the resolution switch.
Bsr SonoraSetResolution ; Switch to the new resolution.
Move.w D0,D1 ; Set up to do the depth switch.
Bra SonoraSetVidModeGuts ; Switch to the new depth.
Endwith
SonoraSetSync ; <sm20>
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = 1) the DB15 Sync
;
; This routine will disable the sync lines going to the DB15 connector
; so that "green-aware" monitors can go into power-saving mode. If we
; are not driving a monitor out of that port, it will return an error.
;
; Note: It might be that in the future, there will be several levels of
; power-saving; Dropping CSYNC- will be one, HSYNC-, another, and
; both syncs another. Since Civic can only drop both, I will ignore
; a second undefined parameter.
;
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates ; <sm20>
; <sm20>
movea.l saveSonoraBase(a3),a0 ; Get Sonora Base (VIA1 base $50f00000) ; <sm20>
adda.l #SonoraVdCtlBase,a0 ; add the difference to get Vid Reg ($28000) ; <sm20>
Move.b SonoraVdModeReg(A0),D0 ; Get the appropriate monitor code. ; <sm20>
; <sm20>
Bset #SonoraVidBlnkBit,D0 ; Set up for SonoraWrite ; <sm20>
MOVE.b csMode(A2),D1 ; get the mode ; <sm20>
Bne.s @WriteToSyncs ; To disable, write a 1 to SonoraSyncEnable ; <sm20>
Bclr #SonoraVidBlnkBit,D0 ; else, write a 0 to enable ; <sm20>
@WriteToSyncs ; <sm20>
Move.b D0,SonoraVdModeReg(A0) ; And disable or enable the sycns ; <sm20>
; <sm20>
BRA SonoraStatGood ; => return no error ; <sm20>
; <sm20>
ENDWITH ; <sm20>
SonoraSetRubik560Mode
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = non-zero) Rubik-560 mode.
;
; Note: ÒEnableÓ means Òswitch from 512 to 560Ó if youÕre
; not already in 560 mode, and ÒdisableÓ means Òswitch
; from Ò560 to 512Ó if youÕre not already in 512 mode.
;
; Also, note that this call will do nothing if we
; were Òstarted upÓ in 560 mode.
;
; Finally, this call only switches the Slot Manager,
; video driver, and hardware data and data structures.
; It is up to the calling application to inform the
; graphics environment (e.g., QuickDraw) that things
; have changed.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With SonoraVidPrivates,SpBlock
; Check to see if we even need to be here or notÉ
;
Btst #InRubik560Mode,GFlags(A3) ; If we Òstarted upÓ in Rubik-560 mode,
Bne SonoraCtlGood ; then thereÕs nothing to do here.
; Check to see if we can even do what was requestedÉ
;
Tst.b csMode(A2) ; If weÕre supposed to be ÒenablingÓ 560 mode,
Beq.s @Chk512 ; check to see if weÕre in 512 mode.
Cmp.b #sRsrc_Vid_Sonora_GS560a,dCtlSlotID(A1) ; If weÕre in 560a mode then,
Beq.s @Setup512a ; set up to switch back to 512a mode.
Cmp.b #sRsrc_Vid_Sonora_GS560b,dCtlSlotID(A1) ; If weÕre in 560b mode then,
Beq.s @Setup512b ; set up to switch back to 512b mode.
Bra SonoraCtlBad ; Otherwise, weÕre not supposed to be here!
@Chk512 Cmp.b #sRsrc_Vid_Sonora_GSa,dCtlSlotId(A1) ; If weÕre in 512a mode then,
Beq.s @Setup560a ; set up to switch to 560a mode.
Cmp.b #sRsrc_Vid_Sonora_GSb,dCtlSlotId(A1) ; If weÕre in 512b mode then,
Beq.s @Setup560b ; set up to switch to 560b mode.
Bra SonoraCtlBad ; Otherwise, weÕre not supposed to here!
; Do the required switchÉ
;
@Setup512a Move.b #sRsrc_Vid_Sonora_GSa,D1 ; Set up for 512a mode.
Bra.s @DoIt
@Setup512b Move.b #sRsrc_Vid_Sonora_GSb,D1 ; Set up for 512b mode.
Bra.s @DoIt
@Setup560a Move.b #sRsrc_Vid_Sonora_GS560a,D1 ; Set up for 560a mode.
Bra.s @DoIt
@Setup560b Move.b #sRsrc_Vid_Sonora_GS560b,D1 ; Set up for 560b mode.
@DoIt Bsr SonoraSetResolution ; Switch to the desired mode.
Bra SonoraCtlGood ; Return good result.
Endwith
SonoraSetAltSense
;---------------------------------------------------------------------
;
; SetAltSense sets up the alternate senseID pRam byte to contain
; a valid ÒindexÓ code if a valid sense code is passed
; in csMode (byte 0 is the sense code, byte 1 is the type).
;
; A1 = Ptr to AuxDCE/Ptr to MonIDs table (not restored)
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With SpBlock,SonoraVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba.w #spBlockSize,Sp ; Make an SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can set it appropriatelyÉ
;
Suba.w #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
;
; See what we need to doÉ
;
Moveq #0,D0 ; Clear D0 for good measure.
Move.b csMode+1(A2),D0 ; Get the sense-code type.
Lea MonIDsTbl,A1 ; Point to the MonIDs table.
@TypeLoop Cmp.w (A1)+,D0 ; If weÕve come to the end of the table,
Bmi.s @MonIDNotValid ; then leave with an error.
Beq.s @ChkOffset ; If weÕve found a match, then check it.
Tst.w (A1)+ ; Otherwise, skip the offset.
Bra.s @TypeLoop ; And keep looping until weÕre done.
@ChkOffset Move.w (A1)+,D1 ; If the offset to the code table is nil,
Beq.s @MonIDNotValid ; then leave with an error.
Lea MonIDsTbl,A1 ; Otherwise, re-point to the MonIDsTbl.
Adda.w D1,A1 ; And point to the appropriate sense-code table.
Move.b csMode(A2),D0 ; Get the sense code.
@CodeLoop Cmp.b (A1)+,D0 ; If weÕve come to the end of the table,
Bmi.s @MonIDNotValid ; then leave with an error.
Beq.s @ChkIt ; If weÕve found a match, then check it.
Tst.b (A1)+ ; Otherwise, skip the indexed code.
Bra.s @CodeLoop ; And keep looping until weÕre done.
@ChkIt Move.b (A1)+,D1 ; Get the indexed ID for this code.
Cmpi.b #indexedNoConnect,D1 ; If itÕs the no-connect code,
Beq.s @ClearIt ; then say so.
Move.b D1,SP_AltSense(Sp) ; Write out ÒindexÓ to pRam record.
Ori.b #spAltSenseValidMask,SP_AltSense(Sp) ; Validate it.
Bra.s @WritePRam
@ClearIt Clr.b SP_AltSense(Sp) ; Invalidate no-connect byte.
@WritePRam Move.l Sp,spsPointer(A0) ; Set up to whack pRam.
_sPutPRAMRec ; Whack it.
Adda.w #SizesPRAMRec+spBlockSize,Sp ; Restore stackÉ
Bra SonoraCtlGood ; Éand leave.
@MonIDNotValid Adda.w #SizesPRAMRec+spBlockSize,Sp ; Restore stackÉ
Bra SonoraCtlBad ; Éleave with error.
Endwith
**********************************************************************
*
* VideoClose releases the device's private storage and removes the
* interrupt handler.
*
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
*
* Other: A2 = temporary AuxDCE pointer copy
*
**********************************************************************
SonoraVidClose
WITH SonoraVidPrivates
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
; Disable interruptsÉ
;
BSR SonoraDisableVGuts ; call utility to deactivate interrupts
; Blank the screenÉ
;
Movea.l saveSonoraBase(A3),A0 ; Get the Sonora base address.
Adda.l #SonoraVdCtlBase,A0 ; Point to the video control register space.
Bset #SonoraVidBlnkBit,SonoraVdModeReg(A0) ; Turn on video blanking.
; Dispose of storageÉ
;
MOVE.L saveSQElPtr(A3),A0 ; get the slot interrupt queue element ptr
_DisposPtr
MOVE.L saveGamDispPtr(A3),A0 ; get pointer to gamma table block
_DisposPtr ; and dispose it
Move.l saveVidPtr(A3),A0 ; Get pointer to video parameters block,
_DisposPtr ; and dispose of it.
MOVE.L dCtlStorage(A1),A0 ; dispose of the private storage
_DisposHandle ;
; Return no errorÉ
;
MOVEQ #noErr,D0 ; no error
RTS ; and return
ENDWITH
**********************************************************************
*
* Video Driver Status Call Handler. There are eleven standard calls:
*
* ($00) Error
* ($01) Error
* ($02) GetMode
* ($03) GetEntries
* ($04) GetPage
* ($05) GetPageBase
* ($06) GetGray
* ($07) GetInterrupt
* ($08) GetGamma
* ($09) GetDefaultMode
* ($0A) GetCurMode
*
* The following calls are Sonora-specific:
*
* ($83) GetAltSense
*
* Entry: A0 = paramblock pointer
* A1 = AuxDCE pointer
* Uses: A2 = cs parameters
* A3 = pointer to private storage
* D0-D3 = scratch (don't need to be preserved)
*
* Exit: D0 = error code
*
**********************************************************************
SonoraVidStatus
MOVEM.L A0/A1,-(SP) ; Save exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
Cmp.w #cscAltSense,D0 ; If we got the AltSense call,
Beq SonoraGetAltSense ; hop to it.
CMP.W #$0D,D0 ;IF csCode NOT IN [0..$0A] THEN
BHI.S SonoraStatBad ; Error, csCode out of bounds.
MOVE.W SonoraStatJumpTbl(PC,D0.W*2),D0 ;Get the relative offset to the routine.
JMP SonoraStatJumpTbl(PC,D0.W) ;GOTO the proper routine.
SonoraStatJumpTbl
DC.W SonoraStatBad-SonoraStatJumpTbl ;$00 => Error
DC.W SonoraStatBad-SonoraStatJumpTbl ;$01 => Error
DC.W SonoraGetMode-SonoraStatJumpTbl ;$02 => GetMode
DC.W SonoraGetEntries-SonoraStatJumpTbl ;$03 => GetEntries
DC.W SonoraGetPage-SonoraStatJumpTbl ;$04 => GetPage
DC.W SonoraGetPageBase-SonoraStatJumpTbl ;$05 => GetPageBase
DC.W SonoraGetGray-SonoraStatJumpTbl ;$06 => GetGray
DC.W SonoraGetInterrupt-SonoraStatJumpTbl ;$07 => GetInterrupt
DC.W SonoraGetGamma-SonoraStatJumpTbl ;$08 => GetGamma
DC.W SonoraGetDefaultMode-SonoraStatJumpTbl ;$09 => GetDefaultMode
DC.W SonoraGetCurMode-SonoraStatJumpTbl ;$0A => GetCurMode
DC.W SonoraGetSyncs-SonoraStatJumpTbl ;$0B => cscGetSync ; <sm20>
DC.W SonoraGetConnection-SonoraStatJumpTbl ;$0C => cscGetConnection
DC.W SonoraGetModeTiming-SonoraStatJumpTbl ;$0D => cscGetModeTiming
SonoraStatBad MOVEQ #statusErr,D0 ; else say we don't do this one
BRA.S SonoraStatDone ; and return
SonoraStatGood MOVEQ #noErr,D0 ; return no error
SonoraStatDone MOVEM.L (SP)+,A0/A1 ; Restore exit registers.
BRA SonoraExitDrvr
SonoraGetMode
;---------------------------------------------------------------------
;
; Return the current mode
;
; Inputs : A2 = pointer to csParams
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVE.W saveMode(A3),csMode(A2) ; return the mode
Clr.w csPage(A2) ; return the page number (always 0)
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the screen baseAddr.
BRA.S SonoraStatGood ; => return no error
ENDWITH
SonoraGetEntries
;---------------------------------------------------------------------
;
; Read the current contents of the CLUT. These values were gamma corrected
; when they were set (by SonoraSetEntries), so they may not match the source
; cSpec array.
;
; Inputs : A1 = pointer to AuxDCE
; A2 = pointer to csParams/CLUT read register (not restored to csParams)
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
With SonoraCLUTRec
Movem.l D4-D6,-(Sp) ; Save work registers.
Tst.l -(Sp) ; Make some room.
Move.l csTable(A2),D0 ; If we were handed a nil pointer,
Beq @GEErr ; then hike.
_StripAddress ; Make table pointer 32-bit clean.
Move.l D0,(Sp) ; And save it.
Move.w saveMode(A3),D1 ; Get the current video mode.
Subi.w #firstVidMode,D1 ; Convert it to an index.
Moveq #0,D3 ; clear all of D3 for .w compare.
Lea SonoraCLUTTbl,A0 ; Point to the table of CLUT data.
Lea (A0,D1*SonoraCLUTSize),A0 ; Point to the right entry.
Move.b scRange(A0),D3 ; Get the CLUT range.
Move.w csCount(A2),D4 ; Get the number of entries to change,
Bmi @GEErr ; and hike if itÕs out of range.
Cmp.w D3,D4 ; If D4-D3 > 0 (count - range > 0),
Bhi @GEErr ; then hike.
Tst.w csStart(A2) ; If weÕre doing indexed entries (-1),
Bmi.s @skipStartChk ; then just go on.
Add.w csStart(A2),D4 ; Adjust count for starting position.
Cmp.w D3,D4 ; If D4-D3 > 0 (count - range > 0),
Bhi @GEErr ; then hike.
@skipStartChk
Move.b scStart(A0),D2 ; Get the starting position.
Move.w scSkip(A0),D5 ; Get the inter-entry skip factor.
Move.w csCount(A2),D6 ; Remember the csCount.
Cmpi.w #indexEntries,csStart(A2) ; If table accesses are to be indexed,
Beq.s @GECom ; then go on.
; The following code is BAD, BAD, BAD! We should build our own table here so
; as to NOT mess up the userÕs data. But all the previous Apple video drivers
; have done the same thing here, so weÕll continue the trend for now.
Move.l (Sp),A0 ; Get ptr to csTable.
Move.w D6,D1 ; Get count.
@TableLoop Move.w D4,value(A0,D1*colorSpecSize) ; Write the index into the table.
Subq #1,D4 ; Decrement index.
Dbra D1,@TableLoop ;
@GECom Move.l (Sp)+,A0 ; Get/restore ptr to csTable.
Move.l saveVDACBase(A3),A2 ; Get VDAC base address.
Add.w #ArielDataReg,A2 ; Add offset to Palette read register.
Move.w Sr,-(Sp) ; Save current interrupt level
Bsr SonoraWaitVSync ; Wait for VBL.
@Repeat Move.w value(A0),D1 ; Get the NEXT Clut position into D1.
Cmp.w D3,D1 ; If this position is out of range,
Bhi.s @Until ; then go on.
Mulu.w D5,D1 ; Multiply index by skip value.
Add.b D2,D1 ; Add in the starting posistion.
Move.b D1,ArielAddrReg-ArielDataReg(A2) ; Tell the Clut where to read from.
Move.b (A2),D1 ; Get Red:
Move.b D1,rgb+red(A0) ; --> $rrXX
Move.b D1,rgb+red+1(A0) ; --> $rrrr
Move.b (A2),D1 ; Get Green:
Move.b D1,rgb+green(A0) ; --> $ggXX
Move.b D1,rgb+green+1(A0) ; --> $gggg
Move.b (A2),D1 ; Get Blue:
Move.b D1,rgb+blue(A0) ; --> $bbXX
Move.b D1,rgb+blue+1(A0) ; --> $bbbb
@Until Addq #colorSpecSize,A0 ; Point to next entry ColorTable.
Dbra D6,@Repeat
Move.w (Sp)+,Sr ; Restore previous interrupt level.
Movem.l (Sp)+,D4-D6 ; Restore work registers.
Bra SonoraStatGood ; Return noError.
@GEErr Tst.l (Sp)+ ; Clean up stack.
Movem.l (Sp)+,D4-D6 ; Restore work registers.
Bra SonoraStatBad ; Return statError.
SonoraGetPage
;---------------------------------------------------------------------
;
; Return the number of pages in the specified mode. It's pretty simple;
; every mode has only one page. We do check if it's valid, however.
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVE csMode(A2),D1 ; get the mode
BSR SonoraChkMode ; is this mode OK?
BNE SonoraStatBad ; => not a valid mode
MOVE.W #1,csPage(A2) ; return page count
BRA SonoraStatGood ; => return no error
ENDWITH
SonoraGetPageBase
;---------------------------------------------------------------------
;
; Return the base address for the specified page in the current mode
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
TST.W csPage(A2) ; are we returning page zero info?
BNE SonoraStatBad ; only page 0 is valid
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the screen baseAddr.
BRA SonoraStatGood ; => return no error
ENDWITH
SonoraGetGray
;---------------------------------------------------------------------
;
; Return a boolean, set true if luminance mapping is on
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVEQ #0,D1 ; set up for BFEXTU
SonoraGetFlagCom
BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag
MOVE.B D0,csMode(A2) ; return value
BRA SonoraStatGood ; => and return
ENDWITH
SonoraGetInterrupt
;---------------------------------------------------------------------
;
; Return a boolean in csMode, set true if VBL interrupts are disabled
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVEQ #1,D1 ; set up BFEXTU to point at IntDisFlag
BRA.S SonoraGetFlagCom ; and use common code
ENDWITH
SonoraGetGamma
;---------------------------------------------------------------------
;
; Return the pointer to the current gamma table
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates
MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure
BRA SonoraStatGood ; and return a good result
ENDWITH
SonoraGetDefaultMode
;---------------------------------------------------------------------
;
; Read the card default mode from slot pRAM.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH spBlock,SonoraVidPrivates,SP_Params
;
; Set up a slot parameter block on the stack.
;
SUBA #spBlockSize,SP ; make an slot parameter block on stack
MOVE.L SP,A0 ; get pointer to parm block now
MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock
CLR.B spExtDev(A0) ; external device = 0
;
; Read the slot pRAM to determine what the currently saved mode is. The first
; byte is the board ID, followed by the default mode. Built-in video keeps the last
; selected video sRsrc spID in VendorUse2.
;
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
MOVE.L SP,spResult(A0) ; point to it
_sReadPRAMRec ; read it
MOVE.B SP_LastConfig(SP),csMode(A2) ; return the result
ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer
BRA SonoraStatGood ;
ENDWITH
SonoraGetCurMode
;---------------------------------------------------------------------
;
; This call will generally be used in conjuntion with the
; the SwitchMode control call. Its function is
; basically to fill out the VDPageInfo with the
; current status. Note that, here, csData, is the
; current SlotID (sResource number) in use.
;
; Note: The implementation of this Status call can be used to
; determine whether the SwitchMode control call is
; implemented or currently accessible.
;
;---------------------------------------------------------------------
With SonoraVidPrivates,VDSwitchInfo
; Check to see if we even need to be here or notÉ
;
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Cmpi.w #indexedSenseMSB2,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Cmpi.w #indexedSenseMSB3,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Bra SonoraStatBad ; Otherwise, just go away.
@EndMSChk
; Return the appropriate information if all is wellÉ
;
Move.w saveMode(A3),csMode(A2) ; Return the current mode (bit depth).
Moveq #0,D0 ; Clear out return-value register.
Move.b dCtlSlotID(A1),D0 ; Get the byte-sized spID.
Move.l D0,csData(A2) ; Make it long.
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the base address for this page.
Clr.w csPage(A2) ; But we only support page #0.
Bra SonoraStatGood ; Vamoose.
Endwith
SonoraGetSyncs ; <sm20>
;---------------------------------------------------------------------
;
; Return a boolean, set true if RGB Syncs are OFF
; Clear the 2nd byte, saying we don't support levels of power-saving.
;
;---------------------------------------------------------------------
WITH SonoraVidPrivates ; <sm20>
; <sm20>
movea.l saveSonoraBase(a3),a0 ; Get Sonora Base (VIA1 base $50f00000) ; <sm20>
adda.l #SonoraVdCtlBase,a0 ; add the difference to get Vid Reg ($28000) ; <sm20>
Move.b SonoraVdModeReg(A0),D0 ; Get the appropriate monitor code. ; <sm20>
; <sm20>
Andi.l #$80,D0 ; and look at bit 7 ; <sm20>
Sne csMode(A2) ; if bit is 1, RGB Syncs are OFF, return true ; <sm20>
Clr.b csMode+1(A2) ; and the next byte for good measure. ; <sm20>
BRA SonoraStatGood ; => and return ; <sm20>
; <sm20>
ENDWITH ; <sm20>
SonoraGetModeTiming
;---------------------------------------------------------------------
;
; This call is used by Display Mgr to determine if a mode is
; valid on a given display. There are 5 possible results
;
; (1) The driver has no idea what this call is and returns statErr.
; This does not apply to the sonora driver
;
; (2) The driver knows with certainty (via sense codes) or via a
; direct connection to the display that the mode in question
; is good. In this case the timing need not be checked with
; an external component for the display. This is the case with
; non-multisync devices and panel displays directly connected by Apple.
;
; (3) The driver is multimode aware and knows there is a multimode monitor
; attached. The driver does not know the exact range of frequencies
; supported by the display and does not know if this mode is supported.
;
; (4) The driver is modeless (many many mode) aware and
;
; (5) The driver gives up control of mode searching to a table in the
; decl ROM. This will be the case for sonora driver.
;
;
; Note: This is a driver call so that
; (1) patches cannot easily be made to the decl data, but can be
; made to the driver. If we want to replace information,
; we can do so in the driver.
; (2) we are not tied to a decl data table format for modeless (many
; many mode) drivers in the future. And if we go to a different
; bus architeture (as people seem to want to) we will not be
; hosed by table based implementations. We may however be
; hosed by driver based implementations, but we can only do
; so much planning for the future and still ship product.
;
;---------------------------------------------------------------------
With SonoraVidPrivates,VDTimingInfo
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Cmpi.w #indexedSenseMSB2,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Cmpi.w #indexedSenseMSB3,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk ; then just keep going.
Bra SonoraStatBad ; Otherwise, just go away.
@EndMSChk
Move.l #kDeclROMtables,csTimingFormat(A2)
Clr.l csTimingData(A2)
Clr.l csTimingFlags(A2)
Bra SonoraStatBad ; Bail Anyway (so DisplayMgr will look in decl ROM).
ENDWITH
SonoraGetConnection
;---------------------------------------------------------------------
;
; This call is used by Display Mgr to get information about the connection
; betrween the display card and the display.
;
; The assumption is that GetConnetion only alters those fields in the
; VDDisplayConnectInfo record for which it has actual information.
; In this case for example, I do not know what the display component
; is so I do not touch it. Same for the csConnectReserved field
;
;---------------------------------------------------------------------
With SonoraVidPrivates,VDDisplayConnectInfo
; ¥¥¥
; For now if we donÕt have a multiscan display we just say that its fixed. (Note: If we really
; wanted to support the Vail-specific family modes here, weÕd want to denote the GS/GS-560
; and the HR/HR-560 display types. Maybe someday.)
;
Move.w #kFixedModeCRTConnect,csDisplayType(A2)
Clr.l csConnectFlags(A2) ; ¥¥¥ Danger: Tagging stuff not complete! ¥¥¥
Clr.w csConnectTagged(A2) ;
; ¥¥¥
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk1 ; then just keep going.
Cmpi.w #indexedSenseMSB2,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk2 ; then just keep going.
Cmpi.w #indexedSenseMSB3,saveMonID(A3) ; If weÕre driving a multiscan display,
Beq.s @EndMSChk3 ; then just keep going.
Bra SonoraStatGood ; Otherwise, just go away.
@EndMSChk1 Move.w #kMultiModeCRT1Connect,csDisplayType(A2)
Bra.s @EndMSChk
@EndMSChk2 Move.w #kMultiModeCRT2Connect,csDisplayType(A2)
Bra.s @EndMSChk
@EndMSChk3 Move.w #kMultiModeCRT3Connect,csDisplayType(A2)
@EndMSChk
Move.l #(1<<kAllModesValid),csConnectFlags(A2)
Bra SonoraStatGood
Endwith
SonoraGetAltSense
;---------------------------------------------------------------------
;
; Returns the alternate senseID code thatÕs in use. It
; should be noted that we cannot disguish between PAL &
; NTSC monitors & encoder boxes once SetAltSense has
; been called (because both the monitor & box codes are
; mapped into the same indexedSense code). We pas back
; this information in csMode (byte 0 is the sense code,
; byte 1 is the type).
;
; A1 = Ptr to AuxDCE/Ptr to MonIDs table (not restored)
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;---------------------------------------------------------------------
With SpBlock,SonoraVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba.w #spBlockSize,Sp ; Make a SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can determine whether the
; alternate senseID code is valid or not.
;
Suba.w #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
Clr.b csMode+1(A2) ; Assume the code is type-0 for now.
Move.b SP_AltSense(Sp),D1 ; Get the alternate senseID byte.
Andi.b #spAltSenseValidMask,D1 ; If it is valid,
Bne.s @Valid ; return it.
Move.b #indexedNoConnect,csMode(A2) ; Otherwise, return the indexed no-connect code,
Bra.s @Exit ; and leave.
@Valid Move.b SP_AltSense(Sp),D1 ; Get the no-connect byte again.
Andi.b #spAltSenseMask,D1 ; Strip the validation code.
Lea Type_0_MonIDs,A1 ; Point to the Type_0_MonIDs.
Bsr @ValidLoop ; Search there.
Move.b #6,csMode+1(A2) ; Assume weÕll find a type-6 sense code.
Lea Type_6_MonIDs,A1 ; Point to the Type_6_MonIDs.
Bsr @ValidLoop ; Search there.
Move.b #7,csMode+1(A2) ; Assume weÕll find a type-7 sense code.
Lea Type_7_MonIDs,A1 ; Point to the Type_7_MonIDs.
Bsr @ValidLoop ; Search there.
Clr.b csMode+1(A2) ; Nothing matchedÉ
Moveq #indexedNoConnect,D0 ; Éso just say no-connect.
@WriteIt Move.b D0,csMode(A2) ; Return valid sense code.
@Exit Adda.w #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra SonoraStatGood ; go home.
@ValidLoop Move.b (A1)+,D0 ; Get the sense code.
Cmp.b (A1)+,D1 ; If the index matches whatÕs in PRAM,
Beq.s @WriteItOut ; then return the sense code.
Tst.b (A1) ; If weÕre at the end of the list,
Bmi.s @ChkNextType ; then move on.
Bra.s @ValidLoop ; Otherwise, loop away.
@WriteItOut Addq #4,Sp ; Clean up the stack.
Bra.s @WriteIt ; And leave.
@ChkNextType Rts
Endwith
;---------------------------------------------------------------------
;
; Exit from Control or Status.
;
; A0 = Ptr to param block.
; A1 = Ptr to AuxDCE.
; D0 = error code.
;
;---------------------------------------------------------------------
SonoraExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
BEQ.S SonoraGoIODone ; => no, not immediate
RTS ; otherwise, it was an immediate call
SonoraGoIODone MOVE.L JIODone,-(Sp) ; Get the IODone address,
Rts ; and go there.
;---------------------------------------------------------------------
;
; ChkMode
;
; Verifies the requested mode is legal. Converts spID in D1 into
; zero-based mode number since lots of people want it that way.
;
; <-> D1: Mode
; -> A3: Pointer to driver privates
;
; All registers preserved
;
; Returns EQ if mode is valid.
;
With SonoraVidPrivates,SonoraVidParams
SonoraChkMode
Movem.l A0/D0,-(Sp) ; Save work registers.
Sub.w #FirstVidMode,D1 ; Make mode zero-based.
Blt.s @ModeBad ; If the passed-in mode is < 0,
; then punt.
Move.l saveVidPtr(A3),A0 ; Get a pointer to the video params.
Tst.b noVRAM(A3) ; If we donÕt have VRAM, then
Bne.s @NoVRAM ; say so.
Adda.w #svpMaxModeBase,A0 ; Point to the base of the max mode values.
Bra.s @GetSize ; Skip the no-VRAM case.
@NoVRAM Adda.w #svpNoRAMMaxBase,A0 ; Point to the base of the no-VRAM modes.
@GetSize Move.b saveSizeVRAM(A3),D0 ; Get the vRAM size index.
Move.b (A0,D0),D0 ; Get the maximum mode for this config.
Sub.w #FirstVidMode,D0 ; Make the max mode zero-based.
Cmp.w D0,D1 ; If the passed-in mode is > max mode,
Bgt.s @ModeBad ; then punt.
Cmp.w D1,D1 ; Set Eq when okay.
@ModeBad Movem.l (Sp)+,A0/D0 ; Restore work registers.
Rts
Endwith
;---------------------------------------------------------------------
;
; Wait for vertical blanking. Interrupts are set to level-2 in
; this routine.
;
; A3 = pointer to private storage
;---------------------------------------------------------------------
With SonoraVidPrivates
SonoraWaitVSync
MOVE.L A0,-(SP) ; Save work registers.
MOVE.L D0,-(SP) ; (Two MOVEs are faster than a MOVEM.)
MOVE.W SR,-(SP) ; Get the status register on stack.
MOVEQ #7,D0 ; Get mask into D0.
AND.B (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
Tst.w (Sp)+ ; Restore stack.
Move.l saveSonoraBase(A3),A0 ; Get the Sonora base address.
Adda.l #SonoraVIA2Base,A0 ; Point to the interrupt register space.
Move.b #$40,SonoraSlotIFR(A0) ; Clear any pending interrupts.
Adda.w #SonoraSlotIFR,A0 ; Point to the interrupt flag register.
@SyncLoop Move.b (A0),D0 ; Read the VBL state.
Btst #6,D0 ; If itÕs none pending (0=pending),
Bne.s @SyncLoop ; then keep looping.
@Done MOVE.L (SP)+,D0 ; Restore work registers.
MOVE.L (SP)+,A0 ; (Two MOVEs are faster than a MOVEM.)
RTS
Endwith
;---------------------------------------------------------------------
;
; SetDepth sets the depth in the DAC and the framebuffer.
;
; D1 contains the spID of the depth - $80 (the zero based mode ID)
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
;---------------------------------------------------------------------
SonoraSetDepth
With SonoraVidPrivates
Movem.l A0/D0-D2,-(Sp) ; Save our work registers.
; Wait for the next VBL before trying to switch depths.
;
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr.s SonoraWaitVSync ; Wait for the next VBL.
; Switch the framebufferÕs depth.
;
Move.l saveSonoraBase(A3),A0 ; Get the Sonora base address.
Adda.l #SonoraVdCtlBase,A0 ; Point to the video control register space.
Move.b D1,SonoraVdColrReg(A0) ; Set the depth.
; Switch the CLUT/DACÕs depth.
;
Move.l saveVDACBase(A3),A0 ; Point to Ariel.
Move.b ArielConfigReg(A0),D0 ; Save the current state.
Andi.b #ClrDepthBitsMask,D0 ; Clear the depth bits.
Or.b D1,D0 ; Turn on the depth bits.
Move.b D0,ArielConfigReg(A0) ; Set the depth.
; Go home.
;
Move.w (Sp)+,Sr ; Restore the interrupt level.
Movem.l (Sp)+,A0/D0-D2 ; Restore the work registers.
Rts ; Return to caller.
Endwith
;---------------------------------------------------------------------
;
; SetResolution gets the video driver and the framebuffer controller
; set up for being switched to a different resolution.
;
; D1 containts the spID to the resolution (mode) to enable.
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
;---------------------------------------------------------------------
SonoraSetResolution
With SonoraVidParams,SpBlock,EgretPB,SonoraOmega
Movem.l D0-D1/A0/A4-A6,-(Sp) ; Save work registers.
Move.b dCtlSlotId(A1),D0 ; Remember which sRsrc to disable.
Move.b D1,dCtlSlotId(A1) ; Remember which sRsrc to enable.
; Do the Slot Manager changesÉ
;
Suba.w #spBlockSize,Sp ; Allocate a slot parameter block on the stack.
Move.l Sp,A0 ; Point to it with A0.
Clr.b spSlot(A0) ; Say that weÕre Slot $0.
Clr.b spExtDev(A0) ; DonÕt ask why, just clear this guy.
Move.b D0,spID(A0) ; Write out the spID of the sRsrc.
_SRsrcInfo ; Update our SpBlock for SUpdateSRT call below.
Move.l #1,spParamData(A0) ; Say that we want it disabled.
_SetSRsrcState ; Do it.
Move.b dCtlSlotId(A1),spID(A0) ; Write out the spID of the sRsrc.
Move.l #0,spParamData(A0) ; Say that we want it enabled.
_SetSRsrcState ; Do it.
_SUpdateSRT ; Tell Slot Manager to update itself (it should really know, but it does not).
; Load the ÒnewÓ video hardware setup blockÉ
;
Clr.w spID(A0) ; Start looking at spID 0, no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Move.b #sVidParmDir,spID(A0) ; Look for the video parameters dir.
_sFindStruct ; Load it.
Move.b dCtlSlotId(A1),spID(A0) ; Look in the directory for this config's parameters.
_sGetBlock ; Load it.
Move.l spResult(A0),-(Sp) ; Save the new privates.
Movea.l saveVidPtr(A3),A0 ; Point to the old privates.
_DisposPtr ; Dispose them.
Move.l (Sp)+,saveVidPtr(A3) ; Start using the new ones.
Adda.w #spBlockSize,Sp ; De-allocate the slot parameter block.
; Change the hardwareÉ
;
Movea.l saveVidPtr(A3),A4 ; Point to vidParams.
Move.l UnivInfoPtr,A6 ; Get a pointer to the ProductInfo table.
Adda.l ProductInfo.DecoderInfoPtr(A6),A6 ; Point to the base address table.
Move.l DecoderInfo.VIA1Addr(A6),A6 ; Get the Sonora base address.
Adda.l #SonoraVdCtlBase,A6 ; Point to the video control address space.
Bset #SonoraVidBlnkBit,SonoraVdModeReg(A6) ; Blank video (to eliminate visual artifacts).
Adda.l #SonoraVIA2Base-SonoraVdCtlBase,A6 ; Point to the VIA2.
Move.b SonoraVRAMSize(A6),D0 ; Pick up the VRAM Sizing parameters.
Adda.l #SonoraVdCtlBase-SonoraVIA2Base,A6 ; Point to the video control address space.
Move.w Sr,-(Sp) ; Save current interrupt level
Bsr SonoraWaitVSync ; Wait for next VBL.
Tst.b noVRAM(A3) ; If we donÕt have real VRAM, then
Bne.s @SkipDotClock ; skip the dot-clock setup.
Movea.l A4,A5 ; Copy the vidParams Ptr.
Cmpi.b #Sonora512Kb,D0 ; If weÕve got 512K on the motherboard
Beq.s @Omega2 ; then weÕve got a new Omega.
Cmpi.b #Sonora768Kb,D0 ;
Bne.s @SetOmega ;
@Omega2 Addq #SOmegaSize,A5 ; Skip past the Omega-1 parameters.
@SetOmega Moveq #0,D0 ; n d p <- 0000000 0000000 00
Move.b SOmegaN(A5),D0 ; n d p <- 0000000 00NNNNN NN
Lsl.w #OmegaDBits,D0 ; n d p <- 00NNNNN NN00000 00
Move.b SOmegaD(A5),D1 ; n d p <- 00NNNNN NN00000 00 (0DDDDDDD)
Or.b D1,D0 ; n d p <- 00NNNNN NNDDDDD DD
Move.b SOmegaP(A5),D1 ; n d p <- 00NNNNN NNDDDDD DD (000000PP)
Lsl.w #OmegaPBits,D0 ; n d p <- NNNNNNN DDDDDDD 00 (000000PP)
Or.b D1,D0 ; n d p <- NNNNNNN DDDDDDD PP
Swap D0 ; Move the ndp value into the MSW.
Or.b #sndSonoraReverseDFAC,D0 ; Move our sound value in.
Suba.w #EgretPBSize,Sp ; Allocate space for the Egret param block on the stack.
Move.l Sp,A0 ; Point to it with A0.
Move.w #(PseudoPkt<<8)+WrDFAC,pbCmdType(A0) ; Say that weÕre writing DFAC.
Move.l D0,pbParam(A0) ; Put out the DFAC data.
Move.w #4,pbByteCnt(A0) ; WeÕre sending 4 bytes.
Clr.w pbResult(A0) ; Clear the result word.
Clr.l pbCompletion(A0) ; No completion routines here.
_EgretDispatch ; Do it.
Adda.w #EgretPBSize,Sp ; De-allocate the Egret parameter block.
@SkipDotClock
Move.b svpMonitorCode(A4),SonoraVdModeReg(A6) ; Write out the appropriate monitor code.
Bsr SonoraWaitVSync ; Wait for next VBL.
Bclr #SonoraVidBlnkBit,SonoraVdModeReg(A6) ; Unblank display.
Move.w (Sp)+,Sr ; Restore the previous interrupt level.
Movem.l (Sp)+,D0-D1/A0/A4-A6 ; Restore the work register.
Rts
Endwith
;---------------------------------------------------------------------
;
; Fill the screen with a 50% dithered gray pattern. To have gotten here
; we must have had a valid display connected, so there are not tests
; for inactive displays here.
;
; D1 = spID of screen depth - FirstVidMode
; A1 = Ptr to AuxDCE
; A3 = driver private storage
;
; All registers are preserved
;
With SonoraVidPrivates,SonoraVidParams
SonoraGrayScreen
Movem.l D0-D5/A1-A2,-(Sp) ; Save our work registers.
Move.l saveBaseAddr(A3),A2 ; Get the base address of the screen.
Move.b dCtlSlotId(A1),D5 ; Get the slotID (which is non-zero).
Cmp.b #sRsrc_Vid_Sonora_GS560a,D5 ; If weÕre driving the Rubik-560a,
Beq.s @Chk1bpp ; then check for 1bpp.
Cmp.b #sRsrc_Vid_Sonora_GS560b,D5 ; If weÕre not driving the Rubik-560b,
Bne.s @GetParms ; then just go on
@Chk1bpp Tst.b D1 ; If weÕre not in 1bpp,
Bne.s @GetParms ; then just go on.
Clr.b D5 ; Otherwise, say rowbytes is wrong.
@GetParms Move.l saveVidPtr(A3),A1 ; Get a pointer to the vidParams.
Move.w svpNumRows(A1),D4 ; Get the number of rows to gray.
Adda.w #SVPHdrSize,A1 ; Skip past the header info.
Move.w (A1,D1*2),D3 ; Get the number of longwords/row.
Lea SonoraPats,A1 ; Point to the table of gray patterns.
Move.l (A1,D1*4),D2 ; Get the gray pattern.
Moveq #true32b,D0 ; Set up to flip into 32-bit addressing mode.
_SwapMMUMode ; Do flip.
@NxtRow Move.l D3,D1 ; Get the number of longswords/row.
@NxtLong Move.l D2,(A2)+ ; Write out gray to the frame bufferÉ
Dbra D1,@NxtLong ; Éfor each scanline.
Tst.b D5 ; If this is not a Rubik-560 at 1bpp,
Bne.s @Skip560 ; then just go on.
Move.w D2,(A2)+ ; Otherwise, write out 16 more pixels.
@Skip560 Not.l D2 ; Invert the pattern for the next row.
Dbra D4,@NxtRow ; Repeat for each row.
_SwapMMUMode ; Switch back to the previous addressing mode.
Movem.l (Sp)+,D0-D5/A1-A2 ; Restore the work registers.
Rts ; Return to caller.
Endwith
;---------------------------------------------------------------------
;
; Trans5to8
;
; <-> D1: 5-bit value to be converted into an 8-bit index.
;
SonoraTrans5to8
Move.l D0,-(Sp) ; Save D0 as scratch.
Moveq #0,D0 ; Clear it.
Move.w D1,D0 ; D1 = ---43210, D0 = ---43210.
Lsl.w #3,D1 ; D1 = 43210---, D0 = ---43210.
Lsr.w #2,D0 ; D1 = 43210---, D0 = -----432.
Or.w D0,D1 ; D1 = 43210432.
Move.l (Sp)+,D0 ; Restore D0.
Rts
;---------------------------------------------------------------------
;
; DirectCLUTSet writes gamma-corrected ascending grayscale-like ramps
; into the CLUT
;
; A3 = dCtlStorage pointer
;
; Preserves all registers used.
;
;---------------------------------------------------------------------
With SonoraVidPrivates
SonoraDirectCLUTSet
MOVEM.L D0-D2/A0/A4-A6,-(SP) ; save registers
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
MOVE.W gFormulaSize(A0),D0 ; get the size of formula data
LEA gFormulaData(A0),A4 ; point to formula data
ADD D0,A4 ; red correction table starts here
MOVE.L A4,A5 ; get default pointer to green data
MOVE.L A4,A6 ; get default pointer to blue data
CMP.W #1,gChanCnt(A0) ; if only only one table, we're set
BEQ.S @OneTbl ; => just one table
MOVE gDataWidth(A0),D1 ; get width of each entry in bits
ADDQ #7,D1 ; round to nearest byte
LSR #3,D1 ; get bytes per entry
MULU gDataCnt(A0),D1 ; get size of table in bytes
ADDA D1,A5 ; calc base of green
ADDA D1,A6 ; calc baseÉ
ADDA D1,A6 ; Éof blue
@OneTbl MOVE.W gDataCnt(A0),D2 ; Get number of entries.
Subq #1,D2 ; Make it zero based.
MOVE.L saveVDACBase(A3),A0 ; point to the hardware
ADDA #ArielDataReg,A0 ; point to data register
CLR.B ArielAddrReg-ArielDataReg(A0) ; start at the beginning of CLUT
Move.w #$1F,D2 ; There are only 32 entries to whack in 16bpp mode.
MOVE.W SR,-(SP) ; preserve the status register
BSR SonoraWaitVSync ; wait for next blanking period (preserves A0)
; Write an incrementing grayscale ramp.
Moveq #0,D0 ; Start the ramp at zero.
@Repeat Move.w D0,D1 ; Copy the current index. <H8>
Bsr.s SonoraTrans5to8 ; Translate from 5-bits to 8.
MOVE.B (A4,D1),(A0) ; Write gamma-corrected red.
MOVE.B (A5,D1),(A0) ; Write gamma-corrected green
MOVE.B (A6,D1),(A0) ; Write gamma-corrected blue.
Addq #1,D0 ; Increment the ramp index.
DBRA D2,@Repeat ; Loop until done.
MOVE.W (SP)+,SR ; restore the status reg
MOVEM.L (SP)+,D0-D2/A0/A4-A6 ; restore saved registers
RTS
Endwith
;-------------------------------------------------------------
; The Interrupt handler for the Sonora Built-In Video
;-------------------------------------------------------------
; On entry A1 contains the pointer to the driver's private storage.
;
With SonoraVidPrivates
SonoraBeginIH
Move.l saveSonoraBase(A1),A0 ; Get the Sonora base address.
Adda.l #SonoraVIA2Base,A0 ; Point to the interrupt register space.
Move.b #$40,SonoraSlotIFR(A0) ; Clear this interrupt.
Moveq #0,D0 ; Set up for Slot $0É
Jsr ([jVBLTask]) ; Éand call the VBL Task Manager.
MOVEQ #1,D0 ; signal that int was serviced
RTS ; and return to caller
Endwith
END