mac-rom/DeclData/DeclVideo/CSC/CSCDriver.a

2858 lines
101 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: CSCDriver.a
;
; Contains: This file contains the video driver for use by the Macintosh
; OS for the CSC hardware.
;
; Written by: Mike Puckett, December 23, 1992.
;
; Copyright: © 1992-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM2> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines
; <1> 01-12-93 jmp first checked in
; <H2> 01-05-93 jmp Conditionally removed the ÒrealÓ interrupt handling code with
; Time Manager based code for bring-up purposes.
; <1> 12-23-92 jmp first checked in
STRING C
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'Video.a'
INCLUDE 'SlotMgrEqu.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'PowerPrivEqu.a'
INCLUDE 'GestaltEqu.a'
INCLUDE 'DepVideoEqu.a'
INCLUDE 'egretequ.a'
PRINT ON
SEG '_sCSCDriver'
BLANKS ON
STRING ASIS
MACHINE MC68020
UsingTimeMgr Equ 1 ; Set if weÕre using a Time Manager Task for VBLs.
DefaultGamma Equ 128
If UsingTimeMgr Then
kCSCVBLTime Equ -16626 ; 60.14742 Hz using the microsecond timer.
Endif
; This is device storage which is stored in the dCtlStorage field of the AuxDCE.
CSCVidPrivates RECORD 0
saveBaseAddr DS.L 1 ; the screen base address
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
saveFixedCLUT DS.L 1 ; pointer to fixed-entry CLUT
saveNumFixedEntries DS.W 1 ; number of entries in fixed CLUT (zero based)
GFlags DS.B 1 ; flags word (hi-order byte, actually)
hasFixedCLUT Ds.b 1 ; if true, CLUT is fixed
saveMode DS.W 1 ; the current mode setting
saveMonID DS.W 1 ; monitor type ID
saveSizeVRAM Ds.b 1 ; amount of vRAM (0=512K,1=1Meg)
useFormulaData Ds.b 1 ; if true, gamma table contains FRC information
If UsingTimeMgr Then
TTask Ds.b tmXQSize ; extended time manger task block
IntDisableFlag Ds.w 1 ; this word is non-zero when interrupts are disabled
Else
saveSQElPtr DS.L 1 ; the SQ element pointer (for _SIntRemove).
Endif
CSCVidPrivSize EQU *
ENDR
;-------------------------------------------------------------------
; Video Driver Header
;-------------------------------------------------------------------
;
CSCVidDrvr Main Export
DC.W $4C00 ; ctl,status,needsLock
DC.W 0,0,0 ; not an ornament
; Entry point offset table
DC.W CSC_VidOpen-CSCVidDrvr ; open routine
DC.W CSCVidDrvr-CSCVidDrvr ; no prime in normal video drivers
DC.W CSC_VidCtl-CSCVidDrvr ; control
DC.W CSC_VidStatus-CSCVidDrvr ; status
DC.W CSC_VidClose-CSCVidDrvr ; close
STRING Pascal
CSCVidTitle
DC.B '.Display_Video_Apple_CSC'
ALIGN 2 ; make sure we're aligned
DC.W CurCSCDrvrVersion ; current version
STRING ASIS
;
; According to CARDS & DRIVERS, video drivers are supposed to shut off
; video at close time Òto avoid the persistence of the desktop
; during reboots.Ó Since we canÕt really turn EscherÕs video off,
; we must simulate it by turning off the backlighting and writing
; white (because itÕs an LCD screen) to the frame buffer. Also,
; because the video driver might be closed and then re-opened
; prior to a reboot (AUX?), we must always re-open the backlight
; driver in the video driverÕs open routine. And, for this reason,
; when we close the backlight driver, we do NOT remove itÕs DCE,
; and do we donÕt dispose of the driver. NOTE: On the first
; time thru (i.e., after startup or restart), the Backlight driver
; will not have been installed yet, so our attempting to open it
; in our open routine will fail, which is okay. This may change
; in the future.
;
String Pascal
CSCBackLite Dc.b '.Backlight' ; Name of Backlight Driver for Escher.
String Asis
Align 2
;
; CSCCLUTTbl 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 bpp mode. The skip factor is the address difference between adjacent active positions
; in each mode.
;
CSCCLUTTbl
DC.B $01,$00,$00,$80 ; for one-bit mode
DC.B $03,$00,$00,$40 ; for two-bit mode
DC.B $0F,$00,$00,$10 ; for four-bit mode
DC.B $FF,$00,$00,$01 ; for eight-bit mode
CSCCLUTRec 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
CSCCLUTSize Equ *
ENDR
;
; These are the rowlongs for each depth.
;
CSCRowLongs Dc.w (OBMLCDRB/4)-1 ; Rowbyts/4 per depth.
Dc.w (TBMLCDRB/4)-1
Dc.w (FBMLCDRB/4)-1
Dc.w (EBMLCDRB/4)-1
Dc.w (D16BMLCDRB/4)-1
;
; These are the bit patterns for grays in each depth.
;
CSCPats Dc.l OneBitGray,TwoBitGray,FourBitGray,EightBitGray,SixteenBitGray
;
; In order to save the state of the CSC across the sleep/wake transition, we need
; to write out the registers themselves as well as the Palette if not in
; 16bpp mode.
;
CSCPalette Dcb.b (256*3),0 ; The saved palette (256 r-g-b entries).
CSCRegs Dcb.w CSCNumRegs+1,0 ; The registers + GTweak.
; 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.
;
; The STNTable is used to tell the Display Manager (in the GetConnection call) whether
; we have a TFT or an STN LCD panel. Things like Kevin HesterÕs mouse tracks use
; this information.
;
CSCSwitchTable
Dc.b sRsrc_Vid_CSC_C_S_TFT_399,FifthVidMode ; Escher
Dc.b sRsrc_Vid_CSC_C_S_TFT_480,FourthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_399a,FifthVidMode ; BlackBird
Dc.b sRsrc_Vid_CSC_C_S_TFT_480a,FourthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_399b,FifthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_480b,FourthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_399c,FifthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_480c,FourthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_399d,FifthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_480d,FourthVidMode
Dc.b sRsrc_Vid_CSC_C_S_TFT_399y,FifthVidMode ; Yeager
Dc.b sRsrc_Vid_CSC_C_S_TFT_480y,FourthVidMode
Dc.b 0,0 ; End
CSCSTNTable Dc.b sRsrc_Vid_CSC_C_D_STN_480 ; Table of FSTN displays.
Dc.b sRsrc_Vid_CSC_G_D_STN_400
Dc.b sRsrc_Vid_CSC_G_D_STN_480
Dc.b sRsrc_Vid_CSC_G_D_STN_400y
Dc.b 0,0 ; End
**********************************************************************
*
* 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,CSCVidPrivates
CSC_VidOpen
;
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
; a pointer to it in A3.
;
MOVEQ #CSCVidPrivSize,D0 ; get size of parameters
_ResrvMem ,SYS ; make room as low as possible
MOVEQ #CSCVidPrivSize,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 (CSC) 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 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.
If UsingTimeMgr Then
Lea CSC_TimeMgrIH,A0 ; Get a pointer to the simulated VBL TimeMgr task.
Move.l A0,tmAddr+TTask(A3) ; Load it into the TimeMgr record.
Lea TTask(A3),A0 ; Get a pointer to the TimeMgr record into A0.
Move.l #'eada',(A0) ; Put in the magic signature to prevent VM from deferring us.
_InsXTime ;
Else
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.
Endif
BSR CSC_EnableVGuts ; 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 #DefaultGamma,spID(A0) ; get the default gamma table
_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 #drHwCSC,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 @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 @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 panel. For extended
; sense panels, we just mapped them to the end of indexed-sense panels. Since the gamma-correction
; code uses the monitor ID to determine if the passed-in table is applicable, we need to know the ÒrealÓ
; panel ID. At PrimaryInit time, we store the real panel ID in slot pRAM. So, we extract that
; information out here.
;
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 @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.
Bfextu D1{spVRamBits:numSPVRamBits},D1 ; Extract the vRAM size from the flags byteÉ
Move.b D1,saveSizeVRAM(A3) ; Éand save it for later.
Bclr #IsSleeping,GFlags(A3) ; Say that weÕre not sleeping now.
;
; Set GFlags to reflect monochrome-only displays.
;
Cmpi.b #sRsrc_Vid_CSC_G_D_STN_400,dCtlSlotId(A1) ; If this is a Mono-Only Panel,
Beq.s @SetMonoFlags ; then say so.
Cmpi.b #sRsrc_Vid_CSC_G_S_TFT_400,dCtlSlotId(A1)
Beq.s @SetMonoFlags
Cmpi.b #sRsrc_Vid_CSC_G_D_STN_480,dCtlSlotId(A1)
Beq.s @SetMonoFlags
Cmpi.b #sRsrc_Vid_CSC_G_S_TFT_480,dCtlSlotId(A1)
Beq.s @SetMonoFlags
Cmpi.b #sRsrc_Vid_CSC_G_D_STN_400y,dCtlSlotId(A1)
Beq.s @SetMonoFlags
Cmpi.b #sRsrc_Vid_CSC_G_S_TFT_400y,dCtlSlotId(A1)
Beq.s @SetMonoFlags
Bra.s @EndMonoCheck
@SetMonoFlags Bset #IsMono,GFlags(A3) ; Turn on the IsMono and
Bset #GrayFlag,GFlags(A3) ; GrayFlag flags.
Cmpi.b #sRsrc_Vid_CSC_G_S_TFT_480,dCtlSlotId(A1) ; If this is the BB-Hosiden panel,
Beq.s @EndMonoCheck ; then just go on.
St hasFixedCLUT(A3) ; Otherwise, say weÕre acting like the GSC.
@EndMonoCheck
; Attempt to re-open the Backlight driver because it might have been closed
; if someone (AUX?) closed us and then tried to reopen us prior to
; rebooting. Currently, this call will fail the first time thru
; because video is installed before backlighting on boot.
;
Moveq #(ioQElSize/2)-1,D0 ; Set up init-loop counter.
@ClrBlk Clr.w -(Sp) ; Allocate and clear param block.
DBra D0,@ClrBlk ; Do it one word at a time.
Lea CSCBackLite,A0 ; Point to Backlight driver name.
Move.l A0,ioFileName(Sp) ; Load it into param block.
Movea.l Sp,A0 ; Get param block pointer into A0.
_Open ; Open driver to get the refNum.
Adda.w #ioQElSize,Sp ; Restore the stack.
;
; 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 CSC/LCD-specific:
*
* ($86) SleepWake (csMode = 0 for sleep, non-zero for wake);
*
* 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É
;
CSC_VidCtl
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
Move.l A0,-(Sp) ; Save A0.
Move.l dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
Move.l (A3),D0 ;
_StripAddress ;
Movea.l D0,A3 ;
Movea.l (Sp)+,A0 ; Restore A0.
Movem.l A0-A3,-(SP) ; Save exit registers.
MOVE.W csCode(A0),D0 ; Get routine selector.
CMP.W #$0A,D0 ; IF csCode NOT IN [0..$0A] THEN
BHI.S OtherCtlRange ; check the other range.
MOVE.W CSCCtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine.
JMP CSCCtlJumpTbl(PC,D0.W) ; GOTO the proper routine.
CSCCtlJumpTbl
DC.W CSC_VidReset-CSCCtlJumpTbl ; $00 => VidReset
DC.W CSCCtlGood-CSCCtlJumpTbl ; $01 => CtlGood (no async routines here)
DC.W CSC_SetVidMode-CSCCtlJumpTbl ; $02 => SetVidMode
DC.W CSC_SetEntries-CSCCtlJumpTbl ; $03 => SetEntries
DC.W CSC_SetGamma-CSCCtlJumpTbl ; $04 => SetGamma
DC.W CSC_GrayPage-CSCCtlJumpTbl ; $05 => GrayPage
DC.W CSC_SetGray-CSCCtlJumpTbl ; $06 => SetGray
DC.W CSC_SetInterrupt-CSCCtlJumpTbl ; $07 => SetInterrupt
DC.W CSCCtlBad-CSCCtlJumpTbl ; $08 => DirectSetEntries (CSC canÕt do it)
DC.W CSC_SetDefaultMode-CSCCtlJumpTbl ; $09 => SetDefaultMode
Dc.w CSC_SwitchMode-CSCCtlJumpTbl ; $0A => SwitchMode
OtherCtlRange Cmpi.w #cscSleepWake,D0 ; $86 => SetSleepWake
Beq CSC_SetSleepWake ;
CSCCtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
BRA.S CSCCtlDone ; and return
CSCCtlGood MOVEQ #noErr,D0 ; return no error
CSCCtlDone MOVEM.L (SP)+,A0-A3 ; Restore Exit registers.
BRA CSCCtlExit
CSC_VidReset
;---------------------------------------------------------------------
; VidReset - <csCode = $01>
;
; Reset the driver to its default mode.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver privates
;
; csParams: csPage.w -> page number
; csBaseAddr.l <- screen base addr
;---------------------------------------------------------------------
With CSCVidPrivates
Tst.b hasFixedCLUT(A3) ; If weÕre not acting like a GSC,
Beq.s @NotFixed ; then skip the GSC-like code.
Move.w #ThirdVidMode,csMode(A2) ; Return the default mode.
Move.w #ThirdVidMode,saveMode(A3) ; Remember which mode was set.
Moveq #(ThirdVidMode-FirstVidMode),D1 ; Get default depth into D1.
Bra.s @VidReset ; Skip non-mono code.
@NotFixed Move.w #FourthVidMode,csMode(A2) ; Return the default mode.
Move.w #FourthVidMode,saveMode(A3) ; Remember which mode was set.
Moveq #(FourthVidMode-FirstVidMode),D1 ; Get default depth into D1.
@VidReset Clr.w csPage(A2) ; Return the page.
Bsr CSC_SetDepth ; Set the depth from D1.
Bclr #IsDirect,GFlags(A3) ; Remember that direct mode is now off.
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the base address.
Bsr CSC_GrayScreen ; Paint the screen gray.
Bra.s CSCCtlGood ; => no error
Endwith
CSC_SetVidMode
;---------------------------------------------------------------------
;
; SetVidMode <csCode = $02>
;
; Puts the video into the specified mode. (We only support page zero.)
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.w -> specified mode
; csPage.w -> page number
; csBaseAddr.l <- screen base addr
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
MOVE.W csMode(A2),D1 ; D1 = mode
BSR CSC_ChkMode ; check mode and convert
BNE.S CSCCtlBad ; => not a valid mode
TST.W csPage(A2) ; only page zero is valid
BNE.S CSCCtlBad ; => not a valid page
; Only set if mode has changed.
CSCSetVidModeGuts
MOVE.W csMode(A2),D3 ; get the mode spID (D1 has the zero-based mode)
CMP.W saveMode(A3),D3 ; has the mode changed?
BEQ @ModeOK1 ; if not, then skip graying
; Remember the newly requested mode.
MOVE.W D3,saveMode(A3) ; remember requested mode
; Set the entire color table to gray before switching to avoid screen anomalies. Note that both
; mono-only panels and color panels set to 16bpp donÕt actually have a CLUT.
Tst.b hasFixedCLUT(A3) ; If weÕre acting like the GSC, then
Bne.s @BlankIt ; we need to blank the screen.
Cmpi.w #FifthVidMode,D3 ; If this is not 16bpp mode,
Blt.s @SetGray ; then just use the CLUT.
@BlankIt Bset #InBlanking,GFlags(A3) ; Say that we want the screen to be blanked.
Bsr CSC_BlankCtl ; And go do it.
Bra.s @SetDepth ; And go switch the depth.
@SetGray 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).
Cmpi.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),D2 ; Save number of gamma entries.
MOVE.L saveVDACBase(A3),A0 ; get the VDAC base addr
ADDA #CSCDataReg,A0 ; point to data register
CLR.B CSCAddrRegW-CSCDataReg(A0) ; start at the beginning of CLUT
MOVE.W SR,-(SP) ; preserve the status register
BSR CSC_WaitVSync ; wait for next blanking period (preserves A0)
; Write out gamma-corrected true-gray CLUTÉ
;
Move.w D2,D0 ; Init loop counter.
Subq #1,D0 ; Zero base it.
Lsr.w #1,D2 ; Get midpoint of table(s).
@Repeat Move.b (A4,D2),(A0) ; Write out red.
Btst #IsMono,GFlags(A3) ; If this is not a mono-only panel,
Beq.s @DoRGB ; then go finish up.
Clr.b (A0) ; Otherwise, just write black outÉ
Clr.b (A0) ; Éto the green & blue channels.
Bra.s @Until ; Skip non-mono stuff.
@DoRGB Move.b (A5,D2),(A0) ; Write: green,
Move.b (A6,D2),(A0) ; blue.
@Until Dbra D0,@Repeat ; Loop until done.
MOVE (SP)+,SR ; restore the status reg
@SetDepth BSR CSC_SetDepth ; set the depth from D1
Tst.b hasFixedCLUT(A3) ; If weÕre not acting like a GSC,
Beq.s @ModeOK ; then just go on.
Move.l saveFixedCLUT(A3),D0 ; If weÕve havenÕt loaded the fixed-entry CLUT,
Beq.s @ModeOK ; just go on.
Move.l D0,A0 ; Otherwise, set up to throw it away.
_DisposPtr ; Throw it awayÉ
Clr.l saveFixedCLUT(A3) ; Éand remember that itÕs gone.
; Finish up the bookkeeping.
@ModeOK CMPI.W #FifthVidMode,D3 ; 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 CSCCtlGood ; return no error
ENDWITH
CSC_SetEntries
;---------------------------------------------------------------------
;
; SetEntries <csCode = $03> - sets the CLUT
;
; 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).
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csTable <- table of colorSpecs (index,R,G,B)
; csStart <- where to start setting, or -1 (for indexed mode)
; csCount <- number of entries to change
;
;---------------------------------------------------------------------
; Initialize loop.
WITH CSCVidPrivates,CSCCLUTRec
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC,
Bne CSCCtlBad ; then we canÕt SetEntries.
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BNE CSCCtlBad ; error if so
CSCSEGuts
TST.L csTable(A2) ; Check for a nil pointer
BEQ CSCCtlBad ;
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 8bpp, then
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 D6 for .w compare.
Lea CSCCLUTTbl,A0 ; Point to the table of CLUT data.
Lea (A0,D1*CSCCLUTSize),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 CSCSEBadExit ; and hike if itÕs out of range.
Cmp.w D4,D3 ; If D3-D4 > 0 (count - range > 0),
Bhi CSCSEBadExit ; 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 CSCSEBadExit ; 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 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 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
Move.b (A4,D0),(A0)+ ; Write gamma corrected red.
Btst #IsMono,D5 ; If this is not a mono-only panel,
Beq.s @Brighter ; then write all three channels.
Clr.b (A0)+ ; Write black for green.
Clr.b (A0)+ ; Write black for blue.
Bra.s @Looper ; Skip non-mono stuff.
@Brighter
MOVE.B (A5,D1),(A0)+ ; write gamma corrected green
MOVE.B (A6,D2),(A0)+ ; write gamma corrected blue
@Looper 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 CSC_WaitVSync ; 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 CSCDataReg(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 CSCSeqWrite ; yup, sequence mode, so go there
;
; Here's the loop that actually writes to the hardware when in indexed mode.
;
CSCIndexWrite
MOVE.B (A0)+,CSCAddrRegW-CSCDataReg(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,CSCIndexWrite ; and loop
BRA.S CSCSEDone ;
;
; Write the translated starting position for sequence mode.
;
CSCSeqWrite
MOVE.W csStart(A2),D0 ; get sequence start address
MOVE.B D0,CSCAddrRegW-CSCDataReg(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.
;
CSCSEDone
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 CSCCtlGood ; return O-Tay!
CSCSEBadExit
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA CSCCtlBad ; return an error code
ENDWITH
CSC_SetGamma
;---------------------------------------------------------------------
;
; SetGamma <csCode = $04>
;
; This call copies the supplied gTable so the caller does not have to put the source
; in the system heap. It tests if the gamma table is exactly a match to the
; currently connected panel, 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
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csGTable <- pointer to gamma table
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC,
Bne CSCCtlBad ; then thereÕs no gamma table.
Btst #IsDirect,GFlags(A3) ; If weÕre in 16bpp mode,
Bne CSCCtlBad ; then we canÕt do gamma either.
; 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
Moveq #0,D2 ; Assume we wonÕt be using formula data.
TST.W gVersion(A2) ; version = 0?
BNE CSCCtlBad ; => no, return error
Tst.w gType(A2) ; Test the hardwareID.
Beq.s @ChangeTable ; If 0, then accept a TFB-style gamma table.
CMP.W #drHwCSC,gType(A2) ; type = CSC?
BNE CSCCtlBad ; => no, return error
TST.W gFormulaSize(A2) ; if gType=CSC, then use gFormulaData
BEQ.S @ChangeTable ; if zero, then generic, so continue
Moveq #1,D2 ; Remember to use formula data if all is well.
; 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 CSCCtlBad ; => 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.b D2,useFormulaData(A3) ; Remember whether or not to use formula data.
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 ;
;
; 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). (DonÕt change
; the useFormalaData state here so that we can swap between corrected
; and uncorrected formulae.)
;
@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
Move.w saveMode(A3),D1 ; Get the current mode into D1.
Sub.w #FirstVidMode,D1 ; Normalize it.
Bsr CSC_SetFRC ; Set the FRC.
BRA CSCCtlGood ; => return no error
ENDWITH
CSC_GrayPage
;---------------------------------------------------------------------
;
; GrayPage <csCode = $05>
;
; Clear the specified page in the current mode to gray.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csPage.w <- page number to gray
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
MOVE saveMode(A3),D1 ; D1 = mode
BSR CSC_ChkMode ; convert mode to depth in D1
BNE CSCCtlBad ; => not a valid depth
MOVE csPage(A2),D0 ; D0 = page
BNE CSCCtlBad ; => not a valid page
BSR CSC_GrayScreen ; paint the screen gray
BRA CSCCtlGood ; => return no error
ENDWITH
CSC_SetGray
;---------------------------------------------------------------------
;
; SetGray <csCode = $06>
;
; Set luminance mapping on or off. When luminance mapping is on, RGB values passed
; to setEntries are mapped to grayscale equivalents before written to the CLUT.
;
; Input: A1 = ptr to dce
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- 1 = mapping on, 0 = mapping off
;
;---------------------------------------------------------------------
WITH CSCVidPrivates,CSCVidParams,CSCBppParams
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 CSCSetIntCom ; call common code
Move.w saveMode(A3),D1 ; Get the current mode.
Sub.w #FirstVidMode,D1 ; Normalize it.
Bsr CSC_SetFRC ; Set the FRC levels.
BRA CSCCtlGood ; 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.
;
CSCSetIntCom
MOVE.B csMode(A2),D0 ; get boolean
BFINS D0,GFlags(A3){D1:1} ; set flag bit
RTS ; and return
ENDWITH
CSC_SetInterrupt
;---------------------------------------------------------------------
;
; SetInterrupt <csCode = $07> - enable/disable 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.
;
; A timer task is used instead of slot interrupts. To disable interrupts, we do not
; re-prime the timer task but we do not remove it from the timer queue. To enable
; interrupts, we re-prime the timer task.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- 0 = enable, non-zero = disable
;
;---------------------------------------------------------------------
WITH VDPageInfo,SlotIntQElement,CSCVidPrivates
If UsingTimeMgr Then
Tst.b csMode(A2) ; Check to see which way weÕre going.
Else
MOVEQ #1,D1 ; set up for BFEXTU to point to IntDisFlag
BSR.S CSCSetIntCom ; call common code
Endif
BNE.S @DisableThem ; If non-zero, then weÕre disabling.
; This code enables interrupts and installs the interrupt handler.
;
BSR.S CSC_EnableVGuts ; call common code
BNE CSCCtlBad ; error, flag problem
BRA CSCCtlGood ; and go home
; This code disables VBL interrupts, then removes the interrupt handler.
;
@DisableThem
BSR.S CSC_DisableVGuts ; jump to the disabling utility
BRA CSCCtlGood ; all done
; The following two routines are common code shared between the Open/Close calls
; and the SetInterrupt control call.
;
CSC_DisableVGuts
If UsingTimeMgr Then
Move.w #1,IntDisableFlag(A3) ; Remember that weÕre disabling things.
Rts
Else
MOVE.W SR,-(SP) ; preserve the status register
BSR CSC_WaitVSync ; to be safe, wait for the next VBL
Move.l saveVDACBase(A3),A0 ; Get the CSC base address.
Bclr #CSCDSIER,CSCDisplayStatus(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
Endif
CSC_EnableVGuts
If UsingTimeMgr Then
Clr.w IntDisableFlag(A3) ; Remember that weÕre enabling things.
MOVE.L A1,-(SP) ; jPrimeTime trashes A1
LEA TTask(A3),A0 ; get time task block in A0
MOVE.L #kCSCVBLTime,D0 ; delay for about 1/60th of a second
MOVE.L jPrimeTime,A1 ; point straight at the Time Manager dispatch vector
JSR (A1) ; start the delay going
MOVEA.L (SP)+,A1 ;
Else
MOVE.L saveSQElPtr(A3),A0 ; get the queue element
LEA CSC_BeginIH,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 saveVDACBase(A3),A0 ; Get the CSC base address.
Bset #CSCDSIFR,CSCDisplayStatus(A0) ; Reset CSC IER/IFR flags.
Bset #CSCDSIER,CSCDisplayStatus(A0) ; Enable Slot $0 interrupts.
Move.l (Sp)+,A0 ; Restore the queue element pointer.
Endif
CMP.W D0,D0 ; clear z-bit for good result
@IntBad RTS ; return home (if bad, z-bit is set above, so just leave)
ENDWITH
CSC_SetDefaultMode
;---------------------------------------------------------------------
;
; SetDefaultMode <csCode = $09> - set default family mode
;
; This routine is called by Monitors when an alternate video mode family in the
; Options dialog is selected.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- video mode to set
;
;---------------------------------------------------------------------
WITH spBlock,CSCVidPrivates,SP_Params
;
; Set up a slot parameter block on the stack.
;
SUBA #spBlockSize,SP ; make a 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.s @BadExit ; If failed, quit.
Move.w spCategory(A0),D0 ; Get the category.
Cmp.w #catDisplay,D0 ; If itÕs not catDisplay,
Bne.s @BadExit ; then quit.
Move.w spCType(A0),D0 ; Get the type.
Cmp.w #typVideo,D0 ; If itÕs not typVideo,
Bne.s @BadExit ; then quit.
Move.w spDrvrSw(A0),D0 ; Get the software kind.
Cmp.w #drSwApple,D0 ; If itÕs not drSwApple,
Bne.s @BadExit ; then quit.
Move.w spDrvrHw(A0),D0 ; Get the hardware ID.
Cmp.w #drHwCSC,D0 ; If itÕs not drHwCSC,
Bne.s @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.
;
; Note: The only family modes supported by CSC are the 399- vs. 480-line. The 399-line
; sRsrcIDs are all even numbers, and the 480-line sRsrcIDs are all odd numbers. We
; use this information to determine whether we should force the depth to 16bpp or
; 8bpp. This is because the only reason anyone would probably want to switch from the
; 480-line mode is so that they get 16bpp, and thereÕs no reason to make people take to
; trips to the Monitors control panel.
;
; Update: If the Display Manager is around, then we donÕt want to go messing around
; with the depth settings.
;
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.
Move.l #gestaltDisplayMgrAttr,D0 ; We need to know if the Display Manager is around.
_Gestalt ; Ask, and ye shall receive.
Bne.s @NoDM ; Oops, got an error.
Move.l A0,D0 ; Get the result into D0.
Btst #gestaltDisplayMgrPresent,D0 ; If the Display Manager is around,
Bne.s @WriteIt ; then skip the non-dynamic stuff.
@NoDM Bset #spFamilyChanged,SP_Flags(Sp) ; Say that weÕre changing the mode.
Btst #0,D1 ; If the sRsrcID weÕre going to is not even,
Bne.s @Set8bpp ; then set up for 8bpp next reboot.
Move.b #FifthVidMode,SP_Depth(Sp) ; Otherwise, default to 16bpp next reboot.
Bra.s @WriteIt ; (Skip.)
@Set8Bpp Move.b #FourthVidMode,SP_Depth(Sp) ; Set up for 8bpp.
@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 CSCCtlGood ; return good result.
@BadExit Adda #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
Bra CSCCtlBad ; return bad result.
ENDWITH
CSC_SwitchMode
;---------------------------------------------------------------------
;
; Some of the panels supported by CSC can be flipped from a 480-line mode
; to a 399-line in order to get 16bpp. This routine allows
; the two 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 CSCVidPrivates,SpBlock,VDSwitchInfo
; Check to see if we can do what was requestedÉ
;
Tst.w csPage(A2) ; If requested page is not zero,
Bne.s CSCCtlBad ; 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 CSCSwitchTable,A0 ; Point to the SwitchMode table.
@ChkLoop Move.b (A0)+,D1 ; If weÕre at the end of the table,
Beq CSCCtlBad ; 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 CSCCtlBad ; 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 CSCSetVidModeGuts ; then go try the depth switch.
Move.b D2,D1 ; Set up to do the resolution switch.
Bsr CSCSetResolution ; Switch to the new resolution.
Move.w D0,D1 ; Set up to do the depth switch.
Bra CSCSetVidModeGuts ; Switch to the new depth.
Endwith
CSC_SetSleepWake
;---------------------------------------------------------------------
;
; SetSleepWake <csCode = 134> - save or restore operating state across
; sleep/wake transition. This routine is called by the sleep or wake
; I/O Primitive code.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b 0 = sleep, non-zero = wake
;
;---------------------------------------------------------------------
With CSCVidPrivates
; Check to see if we even need to be here or notÉ
;
Tst.b csMode(A2) ; If the request was to sleep, then
Beq.s @ChkSleep ; make sure itÕs okay.
Btst #IsSleeping,GFlags(A3) ; Otherwise, if weÕre already awake, then
Beq CSCCtlBad ; somethingÕs wrong.
Bsr CSC_RestoreState ; Go restore the state of the world.
Bsr CSC_EnableVGuts ; Turn cursor interrupts back on.
Bra CSCCtlGood ; And return happy.
@ChkSleep Btst #IsSleeping,GFlags(A3) ; If weÕre already sleeping, then
Bne CSCCtlBad ; somethingÕs wrong.
Bsr CSC_DisableVGuts ; Turn off cursor interrupts for good measure.
Bsr CSC_SaveState ; Save the state of the world.
Bra CSCCtlGood ; And return happy.
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
*
**********************************************************************
CSC_VidClose
WITH CSCVidPrivates
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
; Close the Backlight driver.
;
Moveq #(ioQElSize/2)-1,D0 ; Set up init-loop counter.
@ClrBlk Clr.w -(Sp) ; Allocate and clear param block.
DBra D0,@ClrBlk ; Do it one word at a time.
Lea CSCBackLite,A0 ; Point to Backlight driver name.
Move.l A0,ioFileName(Sp) ; Load it into param block.
Movea.l Sp,A0 ; Get param block pointer into A0.
_Open ; Open driver to get the refNum.
Bne.s @SkipClose ; If open fails, donÕt try to close it.
_Close ; Otherwise, close it.
@SkipClose
Adda.w #ioQElSize,Sp ; Restore the stack.
; Blank the video.
;
Movea.l saveVDACBase(A3),A0 ; Get the CSC base address.
Bclr #CSCPnlPwr,CSCPanelSetup(A0) ; Turn off power.
Bclr #CSCDSRBlankCtl,CSCDisplayStatus(A0) ; Blank video.
; Finish up.
;
If UsingTimeMgr Then
MOVE.W #1,IntDisableFlag(A3) ; set this word to ÒdisableÓ interrupts
LEA TTask(A3),A0 ; get the time manager task block
_RmvTime ; remove this element from the queue
Else
BSR CSC_DisableVGuts ; call utility to deactivate interrupts
MOVE.L saveSQElPtr(A3),A0 ; get the slot interrupt queue element ptr
_DisposPtr
Endif
Movea.l saveGamDispPtr(A3),A0 ; get pointer to gamma table block
_DisposPtr ; and dispose it
Movea.l saveVidPtr(A3),A0 ; Get pointer to video parameters block,
_DisposPtr ; and dispose of it.
Move.l saveFixedCLUT(A3),D0 ; If we havenÕt loaded our fixed-entry CLUT,
Beq.s @NoCLUT ; then just go on.
Movea.l D0,A0 ; Otherwise, dispose of it.
_DisposPtr
@NoCLUT
Movea.l dCtlStorage(A1),A0 ; Dispose of the private storage
_DisposHandle ;
MOVEQ #noErr,D0 ; no error
RTS ; and return
ENDWITH
**********************************************************************
*
* Video Driver Status Call Handler. There are fourteen standard calls:
*
* ($00) Error
* ($01) Error
* ($02) GetMode
* ($03) GetEntries
* ($04) GetPage
* ($05) GetPageBase
* ($06) GetGray
* ($07) GetInterrupt
* ($08) GetGamma
* ($09) GetDefaultMode
* ($0A) GetCurMode
* ($0B) GetSync
* ($0C) GetConnection
* ($0D) GetModeTiming
*
* The following calls are CSC/LCD-specific:
*
* ($86) SleepWake
*
* 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
*
**********************************************************************
CSC_VidStatus
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
Move.l A0,-(Sp) ; Save A0.
Move.l dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
Move.l (A3),D0 ;
_StripAddress ;
Movea.l D0,A3 ;
Movea.l (Sp)+,A0 ; Restore A0.
Movem.l A0-A3,-(SP) ; Save exit registers.
MOVE.W csCode(A0),D0 ; Get routine selector.
CMP.W #$0C,D0 ;IF csCode NOT IN [0..$0C] THEN
BHI.S OtherStatRange ; check other range.
MOVE.W CSCStatJumpTbl(PC,D0.W*2),D0 ;Get the relative offset to the routine.
JMP CSCStatJumpTbl(PC,D0.W) ;GOTO the proper routine.
CSCStatJumpTbl
DC.W CSCStatBad-CSCStatJumpTbl ;$00 => Error
DC.W CSCStatBad-CSCStatJumpTbl ;$01 => Error
DC.W CSC_GetMode-CSCStatJumpTbl ;$02 => GetMode
DC.W CSC_GetEntries-CSCStatJumpTbl ;$03 => GetEntries
DC.W CSC_GetPage-CSCStatJumpTbl ;$04 => GetPage
DC.W CSC_GetPageBase-CSCStatJumpTbl ;$05 => GetPageBase
DC.W CSC_GetGray-CSCStatJumpTbl ;$06 => GetGray
DC.W CSC_GetInterrupt-CSCStatJumpTbl ;$07 => GetInterrupt
DC.W CSC_GetGamma-CSCStatJumpTbl ;$08 => GetGamma
DC.W CSC_GetDefaultMode-CSCStatJumpTbl ;$09 => GetDefaultMode
Dc.w CSC_GetCurMode-CSCStatJumpTbl ;$0A => GetCurMode
Dc.w CSCStatBad-CSCStatJumpTbl ;$0B => GetSync (N/A)
Dc.w CSC_GetConnection-CSCStatJumpTbl ;$0C => GetConnection
OtherStatRange Cmpi.w #cscSleepWake,D0 ;$86 => GetSleepWake
Beq CSC_GetSleepWake ;
CSCStatBad MOVEQ #statusErr,D0 ; else say we don't do this one
BRA.S CSCStatDone ; and return
CSCStatGood MOVEQ #noErr,D0 ; return no error
CSCStatDone MOVEM.L (SP)+,A0-A3 ; Restore exit registers.
BRA CSCStatExit
CSC_GetMode
;---------------------------------------------------------------------
;
; GetMode
;
; Return the current video mode and screen base address
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csmode.w <- current mode
; csPage.w <- current page (always 0)
; csBaseAddr.l <- base address of frame buffer
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
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 CSCStatGood ; => return no error
ENDWITH
CSC_GetEntries
;---------------------------------------------------------------------
;
; GetEntries
;
; Read and return the specified number of consecutive CLUT entries. Like SetEntries,
; GetEntries supports indexed and sequential requests. If the value in csStart is
; positive, then use sequential mode with csStart as the starting address. If the
; value in csStart is -1, then read entries using indexed mode.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csTable.l <-> color table data (i-R-G-B)
; csStart.w <- index to start reading (zero based), or -1 (for indexed mode)
; csCount.w <- number of entries to read (zero based)
;
;---------------------------------------------------------------------
With CSCCLUTRec
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC,
Bne GSC_GetEntries ; then go there now.
Btst #IsDirect,GFlags(A3) ; If weÕre doing 16bpp,
Bne GSC_GetEntries ; then use GSC fixed-type response.
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.
Sub.w #firstVidMode,D1 ; Convert it to an index.
Moveq #0,D3 ; clear all of D3 for .w compare.
Lea CSCCLUTTbl,A0 ; Point to the table of CLUT data.
Lea (A0,D1*CSCCLUTSize),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 ; Save 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 CSC base address.
Add.w #CSCDataReg,A2 ; Add offset to Palette read register.
Move.w Sr,-(Sp) ; Save current interrupt level
Bsr CSC_WaitVSync ; 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,CSCAddrRegR-CSCDataReg(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 CSCStatGood ; Return noError.
@GEErr Tst.l (Sp)+ ; Clean up stack.
Movem.l (Sp)+,D4-D6 ; Restore work registers.
Bra CSCStatBad ; Return statError.
GSC_GetEntries
;---------------------------------------------------------------------
;
; Fake the current contents of the CLUT. There isn't really a clut around,
; but that's no reason not to return a reasonable looking response.
;
; Inputs: A1 = pointer to AuxDCE
; A2 = pointer to csParams
; A3 = pointer to privates
;
; For GSC the color table is fixed. So, weÕll always return good values
; as long as there is a reasonable looking color table around.
;
; Idea: If weÕre in indexed mode, weÕll cycle thru the input
; table. While doing this, weÕll ignore all entries
; whose value fields are out of range. For entries
; whose value field are in range, weÕll return the
; appropriate rgb fields.
;
; If weÕre in sequential mode, we just need to write out
; the number of entries we know about.
;
;---------------------------------------------------------------------
Move.l csTable(A2),D1 ; If we were handed a nil table pointer,
BEQ @GEErr ; then just exit
MOVE.L D1,D0
_StripAddress ; Otherwise, make table pointer 32-bit clean
MOVE.L D0,D3 ; and save it for later
Btst #IsDirect,GFlags(A3) ; If weÕre doing 16bpp,
Bne.s @GEStart ; then skip the non-direct stuff.
Tst.l saveFixedClut(A3) ; If weÕve already loaded the CLUT for this depth,
Bne.s @GEStart ; then just go on.
With SpBlock
LEA -spBlockSize(SP),SP ; Make an SpBlock on the stack and
Move.l Sp,A0 ; get a pointer to it into A0.
Clr.b spSlot(A0) ; WeÕre always in slot 0.
Move.b dCtlSlotID(A1),spID(A0) ; Get the spID of the video sRsrc.
Clr.b spExtDev(A0) ;
_sRsrcInfo ; Try to get the spsPointer.
Bne.s @GESlotErr ; If failed, then quit.
Move.w saveMode(A3),D0 ; If the current mode has been set,
Bne.s @ModeOK ; then go on.
Move.b #FirstVidMode,D0 ; Otherwise, assume 1bpp.
@ModeOK Move.b D0,spID(A0) ; Look for our mode entry.
_sFindStruct ; If itÕs not there,
Bne.s @GESlotErr ; then quit.
Move.b #mTable,spID(A0) ; Get our fixed-entry CLUT.
_sGetBlock ; If itÕs not there,
Bne.s @GESlotErr ; then quit.
Move.l spResult(A0),A0 ; Get a pointer to our fixed-entry CLUT.
Move.w ctSize(A0),saveNumFixedEntries(A3) ; Save the number of entries.
Lea ctTable(A0),A0 ; Get a ptr to the table, and
Move.l A0,saveFixedCLUT(A3) ; save it.
@GESlotErr LEA spBlockSize(SP),SP ; clean up the stack
TST.W D0 ; was there an error?
BNE @GEErr ; -> yes, bail
EndWith
; Calculate the index rangeÉ
;
@GEStart Movea.l D3,A0 ; get pointer to input table.
Moveq #31,D3 ; Assume weÕre doing 16bpp (0..31 entries).
Btst #IsDirect,GFlags(A3) ; If we are, then
Bne.s @SkipFixedCount ; just go on.
Move.w saveNumFixedEntries(A3),D3 ; Otherwise, get number of entries to check against.
@SkipFixedCount
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.w csCount(A2),D2 ; 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, so weÕll continue the trend for now.
Move.w D2,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
@Repeat Move.w value(A0),D1 ; Get the NEXT table position into D1.
Cmp.w D3,D1 ; If this position is out of range,
Bhi.s @Until ; then go on.
Btst #IsDirect,GFlags(A3) ; If weÕre not doing 16bpp,
Beq.s @FixedCLUT ; then used FixedCLUT stuff.
Bsr CSC_Trans5to8 ; Translate 5-bit index to 8 value.
Move.b D1,rgb+red(A0) ; Red: $rrXX,
Move.b D1,rgb+red+1(A0) ; $rrrr.
Move.b D1,rgb+green(A0) ; Green: $ggXX,
Move.b D1,rgb+green+1(A0) ; $gggg.
Move.b D1,rgb+blue(A0) ; Blue: $bbXX,
Move.b D1,rgb+blue+1(A0) ; $bbbb.
Bra.s @Until ;
@FixedCLUT Movea.l saveFixedCLUT(A3),A1 ; Point to start of fixed CLUT.
Lea (A1,D1*colorSpecSize),A1 ; Index into right entry.
Move.w rgb+red(A1),rgb+red(A0) ; Copy red,
Move.w rgb+green(A1),rgb+green(A0) ; green,
Move.w rgb+blue(A1),rgb+blue(A0) ; blue.
@Until Addq #colorSpecSize,A0 ; Point to next entry in input ColorTable.
Dbra D2,@Repeat
Bra CSCStatGood ; Go home.
@GEErr Bra CSCStatBad ;
CSC_GetPage
;---------------------------------------------------------------------
;
; GetPage - return page count
;
; Return the number of pages in the specified mode. Every mode has
; only one page because thatÕs all we support.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csmode.w -> specified mode
; csPage.w <- page count (always 1)
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
MOVE csMode(A2),D1 ; get the mode
MOVE D1,D2 ; keep a copy
BSR CSC_ChkMode ; is this mode OK?
BNE CSCStatBad ; => not a valid mode
MOVE.W #1,csPage(A2) ; return page count
BRA CSCStatGood ; => return no error
ENDWITH
CSC_GetPageBase
;---------------------------------------------------------------------
;
; GetPageBase - return page base address
;
; Return the base address of the specified page in the current mode.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csPage.w -> specified page (always 0)
; csBaseAddr <- base address of page
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
TST.W csPage(A2) ; are we returning page zero info?
BNE CSCStatBad ; only page 0 is valid
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the screen baseAddr.
BRA CSCStatGood ; => return no error
ENDWITH
CSC_GetGray
;---------------------------------------------------------------------
;
; GetGray - return luminance mapping state
;
; Return a boolean whether luminance mapping is on or off.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- 1 = on, 0 = off
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
MOVEQ #0,D1 ; set up for BFEXTU
CSCGetFlagCom
BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag
MOVE.B D0,csMode(A2) ; return value
BRA CSCStatGood ; => and return
ENDWITH
CSC_GetInterrupt
;---------------------------------------------------------------------
;
; GetInterrupt - return VBL interrupt state
;
; Return a boolean whether VBL's are enabled or disabled.
;
; Input: A1 = ptr to dce
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- 1 = disabled, 0 = enabled
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
If UsingTimeMgr Then
TST.W IntDisableFlag(A3) ; test the interrupt state
BEQ.S @isOn ; if not on,
MOVE.B #1,csMode(A2) ; then return disabled state.
BRA CSCStatGood ;
@isOn
CLR.B csMode(A2) ; return enabled state
BRA CSCStatGood
Else
MOVEQ #1,D1 ; set up BFEXTU to point at IntDisFlag
BRA.S CSCGetFlagCom ; and use common code
EndIf
ENDWITH
CSC_GetGamma
;---------------------------------------------------------------------
;
; GetGamma - return ptr to gamma tbl
;
; Return a pointer to the current gamma table.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csGTable.l <- pointer to current gamma table
;
;
;---------------------------------------------------------------------
WITH CSCVidPrivates
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC,
Bne CSCStatBad ; then thereÕs no gamma table.
Btst #IsDirect,GFlags(A3) ; If weÕre in 16bpp mode, then
Bne CSCStatBad ; the gamma table is not being used.
MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure
BRA CSCStatGood ; and return a good result
ENDWITH
CSC_GetDefaultMode
;---------------------------------------------------------------------
;
; GetDefaultMode
;
; Reads the default family mode from slot pRAM.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- default video mode
;
;---------------------------------------------------------------------
WITH spBlock,CSCVidPrivates,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 CSCStatGood ;
ENDWITH
CSC_GetCurMode
;---------------------------------------------------------------------
;
; 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.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
;---------------------------------------------------------------------
With CSCVidPrivates,VDSwitchInfo
; Check to see if we even need to be here or notÉ
;
Moveq #0,D0 ; Clear hi-half of SpID register.
Move.b dCtlSlotID(A1),D0 ; Get the current SpID.
Lea CSCSwitchTable,A0 ; Point to the SwitchMode table.
@ChkLoop Move.b (A0)+,D1 ; If weÕre at the end of the table,
Beq CSCStatBad ; then this mode canÕt switch.
Cmp.b D0,D1 ; If this is not the current mode,
Bne.s @ChkLoop ; then keep looping.
; Return the appropriate information if all is wellÉ
;
Move.w saveMode(A3),csMode(A2) ; Return the current mode (bit depth).
Move.l D0,csData(A2) ; Return the current SpID.
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the base address for this page.
Clr.w csPage(A2) ; But we only support page #0.
Bra CSCStatGood ; Vamoose.
Endwith
CSC_GetConnection
;---------------------------------------------------------------------
;
; This call will generally be used in conjuntion with the
; the SwitchMode control call. Its function is
; to fill out the VDDisplayConnectInfo with the
; right status.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
;---------------------------------------------------------------------
With VDDisplayConnectInfo
Lea CSCSTNTable,A0 ; Point to the table of FSTN displays.
@STNLoop Move.b (A0)+,D0 ; If weÕre at the end of the table,
Beq.s @NotSTN ; then just leave.
Cmp.b dCtlSlotId(A1),D0 ; If we found a match,
Beq.s @FoundOne ; then we have an FSTN display.
Bra.s @STNLoop ; Otherwise, keep looping.
@FoundOne Move.w #kPanelFSTNConnect,csDisplayType(A2); Say that weÕre an STN flat panel display.
Bra.s @GetFlags ;
@NotSTN Move.w #kPanelTFTConnect,csDisplayType(A2) ; Say that weÕre a TFT flat panel display.
@GetFlags Move.l #0|(1<<kAllModesValid)|\, ; Say that all our modes are validÉ
(1<<kAllModesSafe),D0 ; Éand safe to switch to.
Btst #IsMono,GFlags(A3) ; If weÕre not a monochrome display
Beq.s @SetFlags ; then just go on.
Ori.l #(1<<kIsMonoDev),D0 ; Otherwise, say weÕre monochrome.
@SetFlags Move.l D0,csConnectFlags(A2) ;
Bra CSCStatGood ; Vamoose.
Endwith
CSC_GetSleepWake
;---------------------------------------------------------------------
;
; GetSleepWake
;
; Returns the current sleep/wake state of the software/hardware.
;
; Input: A1 = ptr to AuxDCE
; A2 = ptr to csParams
; A3 = ptr to driver globals
;
; csParams: csMode.b <- 0 = sleep, non-zero = wake
;
;---------------------------------------------------------------------
With CSCVidPrivates
Btst #IsSleeping,GFlags(A3) ; Test the sleep/wake flag.
Seq csMode(A2) ; Return result.
Move.l #sleepWakeSig,csData(A2) ; Return the sleepWakeSig.
Bra CSCStatGood ; Vamoose.
Endwith
;---------------------------------------------------------------------
;
; Exit from Control or Status.
;
; A0 = Ptr to param block.
; A1 = Ptr to AuxDCE.
; A2 = cs parameters.
; A3 = pointer to private storage.
;
; D0 = error code.
;
;---------------------------------------------------------------------
With CSCVidPrivates
CSCCtlExit Tst.b hasFixedCLUT(A3) ; If weÕre acting like the GSC, then
Bne.s @UnblankIt ; we need to un-blank the screen.
Btst #IsDirect,GFlags(A3) ; If this is not 16bpp mode,
Beq.s CSCChkQBit ; then just go on.
@UnblankIt Move.w csCode(A0),D1 ; Get the routine selector.
Cmpi.w #cscSetMode,D1 ; If itÕs the SetMode routine,
Beq.s CSCChkQBit ; then donÕt unblank the display.
Cmpi.w #cscSleepWake,D1 ; If itÕs the Sleep/Wake routine,
Beq.s CSCChkQBit ; then donÕt unblank the display.
Bclr #InBlanking,GFlags(A3) ; Say that we want the screen unblanked now.
Bsr CSC_BlankCtl ; And do it.
CSCStatExit
CSCChkQBit BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
BEQ.S CSCGoIODone ; => no, not immediate
RTS ; otherwise, it was an immediate call
CSCGoIODone MOVE.L JIODone,-(Sp) ; Get the IODone address,
Rts ; and go there.
Endwith
;---------------------------------------------------------------------
;
; Trans5to8
;
; <-> D1: 5-bit value to be converted into an 8-bit index.
;
CSC_Trans5to8
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
;---------------------------------------------------------------------
;
; 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 CSCVidPrivates,CSCVidParams
CSC_ChkMode
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.
Adda.w #cscvpMaxModeBase,A0 ; Point to the base of the max mode values.
Moveq #0,D0 ; Clear lo-word of D0 for good measure.
Move.b saveSizeVRAM(A3),D0 ; Get the vRAM size index.
Move.b (A0,D0),D0 ; Get the maximum mode for this config.
Subi.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
;---------------------------------------------------------------------
CSC_WaitVSync
With CSCVidPrivates
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.
Movea.l saveVDACBase(A3),A0 ; Get the CSC base address.
Bset #CSCDSIFR,CSCDisplayStatus(A0) ; Clear any pending interrupts.
Adda.w #CSCDisplayStatus,A0 ; Point to the interrupt flag register.
@SyncLoop Move.b (A0),D0 ; Read the VBL state.
Btst #CSCDSIFR,D0 ; If itÕs none pending (1=pending),
Beq.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
;---------------------------------------------------------------------
;
; CSC_SetFRC sets up either spatial or temporal dithering.
;
; 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
;
CSC_SetFRC
With CSCVidPrivates,CSCVidParams,CSCBppParams
Movem.l A0-A1/D0,-(Sp) ; Save our work registers.
; Get the CSC base address and then determine whether to use the gamma
; table or the vidparam default values
;
Movea.l saveVDACBase(A3),A0 ; Get the CSC base address.
Btst #IsDirect,GFlags(A3) ; If weÕre in direct mode,
Bne.s @UseDefaultData ; then donÕt try to use the gamma table.
Tst.b hasFixedCLUT(A3) ; If weÕre acting like the GSC,
Bne.s @UseDefaultData ; then donÕt try to use the gamma table.
Tst.b useFormulaData(A3) ; If weÕre supposed to use the gamma table,
Bne.s @UseFormulaData ; then do so.
@UseDefaultData
Movea.l saveVidPtr(A3),A1 ; Get a pointer to the vidParams.
Adda.w #CSCVPHdrSize,A1 ; Skip past the header.
Bra.s @SetFRC ; And do it.
@UseFormulaData
Movea.l saveGammaPtr(A3),A1 ; Get a pointer to the gamma table.
Lea gFormulaData(A1),A1 ; Point to the formula data.
; Check to see whether weÕre luminence mapping or not, and then set the FRC
; levels apporpriately.
;
@SetFRC
Moveq #CSCBppSize,D0 ; Get the size of each entry into D0.
Mulu D1,D0 ; Multiply by the right entry.
Adda.w D0,A1 ; Skip to the entry we want.
Btst #GrayFlag,GFlags(A3) ; If weÕre not doing gray, then
Beq.s @DoColor ; apply the color settings.
Move.b cscbpGFRCControl(A1),CSCFRCControl(A0) ; Otherwise, tweak for gray.
Move.b cscbpGPolyMAdj(A1),CSCPolyMAdj(A0) ;
Move.b cscbpGPolyNAdj(A1),CSCPolyNAdj(A0) ;
Bra.s @EndColor ;
@DoColor
Move.b cscbpFRCControl(A1),CSCFRCControl(A0) ; Tweak for color modes.
Move.b cscbpPolyMAdj(A1),CSCPolyMAdj(A0) ;
Move.b cscbpPolyNAdj(A1),CSCPolyNAdj(A0) ;
@EndColor
Movem.l (Sp)+,A0-A1/D0 ; Restore the work registers.
Rts ; Return to caller.
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
;
CSC_SetDepth
With CSCVidPrivates,CSCVidParams,CSCBppParams
Movem.l A0-A1/D0,-(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 CSC_WaitVSync ; Wait for the next VBL.
; Switch the framebufferÕs depth.
;
Move.l saveVDACBase(A3),A0 ; Get the CSC base address.
Move.b D1,CSCDisplayDataForm(A0) ; Set the depth.
Bsr.s CSC_SetFRC ; Set the FRC levels.
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC, then
Bne.s @EndPalette ; just go on.
Cmpi.w #FifthVidMode-FirstVidMode,D1 ; If weÕre not doing 16bpp, then
Bne.s @PaletteOn ; enable palette power.
Bset #CSCPaletteBypass,CSCPanelType(A0) ; Otherwise, disable palette power.
Bra.s @EndPalette ; (Skip the on-switch.)
@PaletteOn Bclr #CSCPaletteBypass,CSCPanelType(A0) ; Enable power to palette.
@EndPalette
; Go home.
;
Move.w (Sp)+,Sr ; Restore the interrupt level.
Movem.l (Sp)+,A0-A1/D0 ; 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
;
;---------------------------------------------------------------------
CSCSetResolution
With CSCVidParams,SpBlock,EgretPB
Movem.l D0-D1/A0-A1,-(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 below.)
Move.l #1,spParamData(A0) ; Say that we want this sRsrc 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 the Slot Manager to update itself.
; 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),A1 ; Point to the vidParams.
Movea.l saveVDACBase(A3),A0 ; Point to the CSC base address.
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr.s CSC_WaitVSync ; Wait for the next VBL.
Move.b cscvpPanelType(A1),CSCPanelType(A0) ; Set up for the attached panel.
Move.b cscvpPanelSetup(A1),D0 ; Get the non-powered PanelSetup param.
Bset #CSCPnlPwr,D0 ; Set the PanelPower bit.
Move.b D0,CSCPanelSetup(A0) ; Write out PanelSetup.
Move.b cscvpHSkewHi(A1),CSCHSkewHi(A0) ; Set up the H/V timing.
Move.b cscvpHSkewLo(A1),CSCHSkewLo(A0) ;
Move.b cscvpVSkewHi(A1),CSCVSkewHi(A0) ;
Move.b cscvpVSkewLo(A1),CSCVSkewLo(A0) ;
Move.b cscvpACDClkHi(A1),CSCACDClkHi(A0) ; Set up the clocking.
Move.b cscvpACDClkLo(A1),CSCACDClkLo(A0) ;
Move.b cscvpLPStart(A1),CSCLPStart(A0) ;
Move.b cscvpLPWidth(A1),CSCLPWidth(A0) ;
Move.b cscvpFLMControl(A1),CSCFLMControl(A0) ;
; Clean up and go homeÉ
;
Move.w (Sp)+,Sr ; Restore the interrupt level.
Movem.l (Sp)+,D0-D1/A0-A1 ; Restore the work registers.
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 CSCVidPrivates,CSCVidParams
CSC_GrayScreen
Movem.l D0-D6/A1-A2,-(Sp) ; Save our work registers.
Move.l saveBaseAddr(A3),A2 ; Get the base address of the screen.
Move.b dCtlSlotID(A1),D5 ; Remember which screen this is.
Move.l saveVidPtr(A3),A1 ; Get a pointer to the vidParams.
Move.w cscvpNumRows(A1),D4 ; Get the number of rows to gray.
Move.w D4,D6 ; Remember them.
Lea CSCRowLongs,A1 ; Point to the table of rowlongs.
Move.w (A1,D1*2),D3 ; Get the right entry for this depth.
Lea CSCPats,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.
Move.b D0,-(Sp) ; Save previous addressing mode.
@NxtRow Move.l D3,D0 ; Get the number of longswords/row.
@NxtLong Move.l D2,(A2)+ ; Write out gray to the frame bufferÉ
Dbra D0,@NxtLong ; Éfor each scanline.
Not.l D2 ; Invert the pattern for the next row.
Dbra D4,@NxtRow ; Repeat for each row.
Cmpi.w #(defmBounds_BLCD-1)-1,D6 ; If weÕre not doing the 16bpp Ò400-lineÓ panel,
Bne.s @SwapBack ; then just go on.
Moveq #IndexedBlack,D2 ; Assume weÕre in an indexed mode.
Cmpi.w #FifthVidMode-FirstVidMode,D1 ; If this is an indexed mode,
Blt.s @StartBlack ; then just go on.
Moveq #DirectBlack,D2 ; Otherwise, set up for direct mode.
@StartBlack Move.w D3,D0 ; Get the number of longwords/row.
@LastLine Move.l D2,(A2)+ ; Write out black to the last line ofÉ
Dbra D0,@LastLine ; Éto whole last line.
@SwapBack Move.b (Sp)+,D0 ; Set up to switch back to previous addressing mode
_SwapMMUMode ; Do flip.
Movem.l (Sp)+,D0-D6/A1-A2 ; Restore the work registers.
Rts ; Return to caller.
Endwith
;---------------------------------------------------------------------
;
; SaveState saves the operating state of the framebuffer controller,
; CLUT/DAC, etcÉ, for the sleep/wake transition.
;
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
With CSCVidPrivates
CSC_SaveState
Bset #IsSleeping,GFlags(A3) ; Remember that weÕve been asked to sleep.
Movem.l D0/A0/A4-A5,-(Sp) ; Save some work registers.
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr.s CSC_WaitVSync ; Wait for the next VBL.
Movea.l saveVDACBase(A3),A5 ; Get the CSC base address.
; Tell the PowerManager that the LCD is to be turned off.
;
Move.b #screenOff,-(Sp) ; Put the off-switch into the buffer.
Move.l Sp,-(Sp) ; pmRBuffer
Move.l (Sp),-(Sp) ; pmSBuffer
Move.w #1,-(Sp) ; pmLength = 1
Move.w #power1Cntl,-(Sp) ; pmCommand
Movea.l Sp,A0 ; Point to the param block.
_PMgrOp ; Turn the LCD screen on/off.
LEA pmCommandRec.pmRBuffer+4+2(Sp),Sp ; Toss the param block.
_CSCMaxDelay ; Wait 50 ms.
; First, check to see if we need to save the state of the palette.
;
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC,
Bne.s @SaveRegs ; then just save the regs.
Btst #IsDirect,GFlags(A3) ; If weÕre in 16bpp mode, then
Bne.s @SaveRegs ; then just save the regs.
; Save the state of the PaletteÉ
;
Lea CSCPalette,A4 ; Point to the palette holding area.
Movea.l A5,A0 ; Get CSC base address.
Adda.w #CSCDataReg,A0 ; Add offset to Palette data register.
Clr.b CSCAddrRegR-CSCDataReg(A0) ; Tell the Palette to start with entry 0.
Move.w #256-1,D0 ; Init the counter.
@PlttLoop Move.b (A0),(A4)+ ; Read red,
Move.b (A0),(A4)+ ; green,
Move.b (A0),(A4)+ ; blue.
Dbra D0,@PlttLoop ; Loop until done.
; Save the state of the RegistersÉ
;
@SaveRegs Bclr #CSCDSRBlankCtl,CSCDisplayStatus(A5) ; Blank the display.
Bclr #CSCPnlPwr,CSCPanelSetup(A5) ; Disable panel power.
Lea CSCRegs,A4 ; Point to the register holding area.
Movea.l A5,A0 ; Point to the CSC base address.
Adda.w #CSCFrstReg,A0 ; Point to the first save/restore reg.
Move.w #CSCNUMRegs-1,D0 ; Init the counter.
@RegLoop Move.w (A0)+,(A4)+ ; Save a reg.
Dbra D0,@RegLoop ; Loop until done.
Move.w CSCGTweak(A5),(A4) ; Save the GTweak register, as well.
; Clean up and go homeÉ
;
Move.w (Sp)+,Sr ; Restore the interrupt level.
Movem.l (Sp)+,D0/A0/A4-A5 ; Restore the work registers.
Rts
Endwith
;---------------------------------------------------------------------
;
; RestoreState restores the operating state of the framebuffer controller,
; CLUT/DAC, etcÉ, for the sleep/wake transition.
;
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
With CSCVidPrivates
CSC_RestoreState
Movem.l D0-D1/A0/A4-A5,-(Sp) ; Save some work registers.
Movea.l saveVDACBase(A3),A5 ; Get the CSC base address.
; First, check to see if we need to restore the state of the palette.
;
Tst.b hasFixedCLUT(A3) ; If weÕre acting like a GSC,
Bne.s @SaveRegs ; then just save the regs.
Btst #IsDirect,GFlags(A3) ; If weÕre in 16bpp mode, then
Bne.s @SaveRegs ; then just save the regs.
; Save the state of the PaletteÉ
;
Lea CSCPalette,A4 ; Point to the palette holding area.
Movea.l A5,A0 ; Point to the CSC base address.
Adda.w #CSCDataReg,A0 ; Add offset to Palette data register.
Clr.b CSCAddrRegW-CSCDataReg(A0) ; Tell the Palette to start with entry 0.
Move.w #256-1,D0 ; Init the counter.
@PlttLoop Move.b (A4)+,(A0) ; Write red,
Move.b (A4)+,(A0) ; green,
Move.b (A4)+,(A0) ; blue.
Dbra D0,@PlttLoop ; Loop until done.
; Save the state of the RegistersÉ
;
@SaveRegs Lea CSCRegs,A4 ; Point to the register holding area.
Movea.l A5,A0 ; Point to the CSC base address.
Adda.w #CSCFrstReg,A0 ; Point to the first save/restore reg.
Move.w #CSCNUMRegs-1,D0 ; Init the counter.
@RegLoop Move.w (A4)+,(A0)+ ; Save a reg.
Dbra D0,@RegLoop ; Loop until done.
Move.w (A4),CSCGTweak(A5) ; Restore the GTweak register.
; Gray the VRAMÉ
;
Move.w saveMode(A3),D1 ; Get the current mode.
Subi.w #FirstVidMode,D1 ; Normalize it.
Bsr CSC_GrayScreen ; Gray the screen.
; Turn the display back onÉ
;
Move.b #CSCNoMask,CSCMaskReg(A5) ; Enable all video data in the Palette (if necessary).
Bset #CSCDSRBlankCtl,CSCDisplayStatus(A5) ; Unblank the video display.
Bset #CSCPnlPwr,CSCPanelSetup(A5) ; Enable panel power.
_CSCMaxDelay ; Wait 50 ms.
Move.b #screenOn,-(Sp) ; Put the on-switch into the buffer.
Move.l Sp,-(Sp) ; pmRBuffer
Move.l (Sp),-(Sp) ; pmSBuffer
Move.w #1,-(Sp) ; pmLength = 1
Move.w #power1Cntl,-(Sp) ; pmCommand
Movea.l Sp,A0 ; Point to the param block.
_PMgrOp ; Turn the LCD screen on/off.
LEA pmCommandRec.pmRBuffer+4+2(Sp),Sp ; Toss the param block.
Movem.l (Sp)+,D0-D1/A0/A4-A5 ; Restore the work registers.
Bclr #IsSleeping,GFlags(A3) ; Remember that weÕre no longer asleep.
Rts
Endwith
CSC_BlankCtl
;---------------------------------------------------------------------
;
; BlankCtl exists only because MacsBug draws the user framebuffer
; BEFORE calling SetMode when it is switching depths. Because
; we want to simulate the effect of a CLUT (by having a solid
; gray during depth switches), we use the blankshade register.
; Normally, weÕd couple this with a call to GrayScreen, but
; we canÕt because of the order in which MacsBug calls SetMode
; and redraws the screen. To get around this problem, we
; temporarily say we have a CLUT, which forces MacsBug
; to call us back (with SetEntries), and thatÕs where we
; unblank the screen and re-assert ourselves as a fixed
; gDevice. For direct devices, we donÕt have to worry
; about doing the CLUT swap.
;
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
Movem.l D0-D1/A0,-(Sp) ; Save some working registers.
Move.l Devicelist,D0 ; If the DeviceList Handle is nil, then
Beq.s @Done ; we canÕt do anything useful here.
Movea.l saveVDACBase(A3),A0 ; Point to the CSC base address.
Btst #InBlanking,GFlags(A3) ; If weÕre supposed to be blanking the LCD,
Bne.s @BlankIt ; then do it.
Bset #CSCDSRBlankCtl,CSCDisplayStatus(A0) ; Otherwise, unblank it.
Bra.s @EndBlank ; Move along.
@BlankIt Bclr #CSCDSRBlankCtl,CSCDisplayStatus(A0) ; Blank the screen.
@EndBlank
Tst.b hasFixedCLUT(A3) ; If weÕre not acting like a GSC,
Beq.s @Done ; then weÕre done.
Move.w dCtlRefNum(A1),D1 ; Get the driverÕs refNum.
@DevLoop Movea.l D0,A0 ; Get Handle to gDevice.
Movea.l (A0),A0 ; Make it a pointer.
Cmp.w gdRefNum(A0),D1 ; If this isnÕt our gDevice,
Bne.s @NextGD ; then just go on.
Btst #InBlanking,GFlags(A3) ; If weÕve blanked the screen, then
Bne.s @ClutIt ; temporarily act like weÕve got a CLUT.
Move.w #fixedType,gdType(A0) ; Otherwise, put things back.
Bra.s @Done ; Vamoose.
@ClutIt Move.w #clutType,gdType(A0) ; MacsBug is happier this way.
Bra.s @Done ; Vamoose.
@NextGD Move.l gdNextGD(A0),D0 ; If the next gDeviceÕs Handle isnÕt nil,
Bne.s @DevLoop ; then loop until done
@Done Movem.l (Sp)+,D0-D1/A0 ; Restore working registers.
Rts
;-------------------------------------------------------------
; The Interrupt handler for the CSC Built-In Video
;-------------------------------------------------------------
; On entry A1 contains the pointer to the driver's private storage
; D0-D3/A0-A3 have been preserved.
If UsingTimeMgr Then
CSC_TimeMgrIH
MOVE.L A1,-(SP) ; save A1 (it's trashed by JVBLTask)
CLR.W D0 ; set slot zero in D0
MOVE.L JVBLTask,A0 ; call the VBL task manager
JSR (A0) ; with slot # in D0
MOVEA.L (SP)+,A1 ; restore A1 (ptr to TTask block)
TST.W tmXQSize(A1) ; test the flag word to see if ÒinterruptsÓ are on
; WARNING! - this field must be immediately after the TTask elem
BNE.S @Done ; if ­ 0, then ÒinterruptsÓ are disabled, so don't reprime
MOVEA.L A1,A0 ; get time task block addr in A0
MOVE.L #kCSCVBLTime,D0 ; delay for about 1/60th of a second
MOVE.L jPrimeTime,A1 ; point straight at the Time Manager dispatch vector
JSR (A1) ; start the delay going
@Done
RTS ; and return to caller
Else
With CSCVidPrivates
CSC_BeginIH
Move.l saveVDACBase(A1),A0 ; Get the CSC base address.
Btst #CSCDSIFR,CSCDisplayStatus(A0) ; If this wasnÕt our interrupt,
Beq.s @NotUs ; then say so.
Bset #CSCDSIFR,CSCDisplayStatus(A0) ; Otherwise, clear it.
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
@NotUs Moveq #0,D0 ; Say that we didnÕt do anything.
Rts ; And leave.
Endwith
Endif
End