mac-rom/DeclData/DeclVideo/Sonora/SonoraDriver.a
Elliot Nunn 0ba83392d4 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-09-20 18:04:16 +08:00

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