mirror of
https://github.com/elliotnunn/boot3.git
synced 2024-05-28 15:41:27 +00:00
5b0f0cc134
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.
2858 lines
101 KiB
Plaintext
2858 lines
101 KiB
Plaintext
;
|
||
; 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 |