mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-02-05 07:31:15 +00:00
4325cdcc78
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.
1292 lines
46 KiB
Plaintext
1292 lines
46 KiB
Plaintext
;
|
||
; File: DBLite.a
|
||
;
|
||
; Contains: This file contains the video driver for use by the Macintosh
|
||
; OS for the GSC hardware (PowerBooks 160, 180, Duo 210, Duo 230).
|
||
;
|
||
; Written by: Mike Puckett
|
||
;
|
||
; Copyright: © 1991-1993 by Apple Computer, Inc. All rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM5> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
|
||
; machines
|
||
; <SM4> 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
|
||
; <SM3> 11/2/92 kc Don't include SonicEqu.a.
|
||
; <SM7> 10/22/92 CSS Fix short branch to regular branch.
|
||
; <1> 10/6/92 GDW New location for ROMLink tool.
|
||
; <SM5> 09-03-92 jmp Clean-up some mistakes in <SM4>Õs check-in comments.
|
||
; <SM4> 09-03-92 jmp (SWC,H18) DBLite once again uses a Time Manager task instead of
|
||
; the GSC interrupt because we were seeing cursor breakup at the
|
||
; top of the screen.
|
||
; (SWC,H17) Rolled the refresh/skew table lookup code back in (it
|
||
; seems to have been deleted sometime between <H10> and now...)
|
||
; Hopefully now using the final GSC refresh/skew values for
|
||
; DBLite.
|
||
; (jmp,H16) Corrected .s vs. non-.s branches.
|
||
; (djw,H15) Removed DBLiteGetVidAttributes call to avoid adding
|
||
; new Apple "required" calls to video drivers.
|
||
; (HJR,H14) Removed control LowPwrSelect since it may cause too
|
||
; much confusion between dimming and sleep.
|
||
; (HJR,H13) Added new control call, LowPwrSelect for dimming. Also
|
||
; fixed a bug in SetDepth whether there was improper register useage.
|
||
; (djw,H12) Added DBLiteGetVidAttributes status call with a
|
||
; negative csCode (-16384). Fix bug in Control and status common
|
||
; dispatcher dealing with the extended table. Fixed bug in
|
||
; DBLiteBlankScreen control routine.
|
||
; (HJR,H11) Added DBLiteBlankScreen routine to clear the screen.
|
||
; Added a 33 millisecond delay in SetDepth to help with a DSack
|
||
; problem. Modifies DBLiteCSCommon to handle additional Cntrl and
|
||
; Status calls. In DBLiteVidClose, turn off the backlight driver
|
||
; and blank the screen. In DBLiteVidOpen, open the backlight
|
||
; driver.
|
||
; (SWC,H10) Changed bit depth code to change both the skew and
|
||
; refresh rate together since the two values are interdependent.
|
||
; <SM3> 5/16/92 kc Roll in Horror Changes. Comments follow:
|
||
; <H9> 4/16/92 SWC Added adjustment of the GSC's skew register based on the bit
|
||
; depth.
|
||
; <H8> 3/12/92 SWC Save D0 across the StripAddress in the control/status code so
|
||
; that we can return the correct error code. Fixed a bug in
|
||
; GetEntries that always caused us to return the 1-bit entry
|
||
; table.
|
||
; <H7> 2/13/92 HJR Fix header in <H6>.
|
||
; <H6> 2/13/92 HJR Added Time Manager pseudo panel interrupts to Niagra machines
|
||
; since it does not support real interrupts from the GSC.
|
||
; <H5> 1/16/92 SWC Did a bit more driver cleanup.
|
||
; <H4> 1/13/92 SWC Removed the GrayScreen call in SetDepth since we ended up with a
|
||
; gray screen instead of "real stuff" when exiting Macsbug.
|
||
; Replace the Time Manager pseudo panel interrupts with the real
|
||
; thing from the GSC. Cleaned up the driver code a bit.
|
||
; <H3> 12/10/91 HJR Fixed some minor table lookup bugs.
|
||
; <H2> 11/26/91 jmp Added VERY preliminary support for the GSC.
|
||
; <2> 3/31/92 JSM Rolled this file into Reality.
|
||
; <2> 5/22/91 jmp Code Review changes: For consistency, did a StripAddress on
|
||
; VidOpenÕs copy of the privates; eliminated the redundant clears
|
||
; and checks for the the driver copy of the fixed-entry clut; and
|
||
; replaced #0Õs with #noErrÕs where appropriate.
|
||
; <1> 5/15/91 jmp first checked in
|
||
;
|
||
|
||
STRING C
|
||
|
||
PRINT OFF
|
||
LOAD 'StandardEqu.d'
|
||
|
||
INCLUDE 'DockingEqu.a'
|
||
INCLUDE 'EgretEqu.a'
|
||
INCLUDE 'GestaltEqu.a'
|
||
INCLUDE 'GestaltPrivateEqu.a'
|
||
INCLUDE 'HardwarePrivateEqu.a'
|
||
INCLUDE 'IOPrimitiveEqu.a'
|
||
INCLUDE 'PowerPrivEqu.a'
|
||
INCLUDE 'ROMEqu.a'
|
||
INCLUDE 'Video.a'
|
||
INCLUDE 'SlotMgrEqu.a'
|
||
INCLUDE 'ShutDown.a'
|
||
; INCLUDE 'SonicEqu.a'
|
||
INCLUDE 'UniversalEqu.a'
|
||
|
||
INCLUDE 'DepVideoEqu.a'
|
||
PRINT ON
|
||
|
||
SEG '_sDBLiteDriver'
|
||
|
||
BLANKS ON
|
||
STRING ASIS
|
||
MACHINE MC68020
|
||
|
||
|
||
kDBLiteVBLTime EQU -16626 ; 60.14742 Hz using the microsecond timer.
|
||
|
||
; This is device storage which is stored in the dCtlStorage field of the AuxDCE.
|
||
|
||
DBLiteVidPrivates RECORD 0
|
||
saveBaseAddr DS.L 1 ; the screen base address
|
||
saveGSCAddr DS.L 1 ; the ÔVDACÕ (GSC) base address
|
||
saveFixedCLUT DS.L 1 ; pointer to fixed-entry CLUT
|
||
saveNumFixedEntries DS.W 1 ; number of entries in fixed CLUT (zero based)
|
||
GFlags DS.W 1 ; flags word (hi-order byte, actually)
|
||
saveMode DS.W 1 ; the current mode setting
|
||
TTask DS.B tmXQSize ; extended time manager task block
|
||
IntDisableFlag DS.W 1 ; this word is non-zero when the VBL interrupt
|
||
DBLiteVidPrivSize EQU *
|
||
ENDR
|
||
|
||
|
||
|
||
LDBLiteDriver MAIN EXPORT
|
||
|
||
;-------------------------------------------------------------------
|
||
; Video Driver Header
|
||
;-------------------------------------------------------------------
|
||
;
|
||
DBLiteDrvr DC.W $4C00 ; ctl,status,needsLock
|
||
DC.W 0,0,0 ; not an ornament
|
||
|
||
; Entry point offset table
|
||
|
||
DC.W DBLiteVidOpen-DBLiteDrvr ; open routine
|
||
DC.W DBLiteDrvr-DBLiteDrvr ; no prime
|
||
DC.W DBLiteVidCtl-DBLiteDrvr ; control
|
||
DC.W DBLiteVidStatus-DBLiteDrvr ; status
|
||
DC.W DBLiteVidClose-DBLiteDrvr ; close
|
||
|
||
STRING Pascal
|
||
DBLiteVidTitle DC.B '.Display_Video_Apple_GSC'
|
||
ALIGN 2 ; make sure we're word aligned
|
||
DC.W CurGSCDrvrVersion ; 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 DBliteÕ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
|
||
DBLiteBackLite Dc.b '.Backlight' ; Name of Backlight Driver for DBLite.
|
||
String Asis
|
||
Align 2
|
||
;
|
||
; The following table is used by the GrayScreen routine for drawing the 50% gray pattern
|
||
; at the appropriate bit depth. The Ònumber of rowsÓ entry is for future expansion --
|
||
; that is, if we ever need to distinguish between 640x400 vs. 640x480 panels.
|
||
;
|
||
|
||
DBGrayTblRec Record 0
|
||
grayTblPat Ds.l 1 ; The bit-pattern to use at this depth.
|
||
grayTblRow Ds.w 1 ; The (number of longwords)-1 at this depth.
|
||
grayTblCol Ds.w 1 ; The (number of rows)-1 at this depth.
|
||
DBGrayTblSize Equ *
|
||
Endr
|
||
|
||
DBLiteGrayTbl
|
||
Dc.l OneBitGray ; 1bpp
|
||
Dc.w (OBMLCDRB/4)-1,defmBounds_BLCD-1 ;
|
||
|
||
Dc.l TwoBitGray ; 2bpp
|
||
Dc.w (TBMLCDRB/4)-1,defmBounds_BLCD-1 ;
|
||
|
||
Dc.l FourBitGray ; 4bpp
|
||
Dc.w (FBMLCDRB/4)-1,defmBounds_BLCD-1 ; <H3>
|
||
|
||
;
|
||
; In order to save the state of the GSC across the sleep/wake transition, we need
|
||
; to write out the registers themselves.
|
||
;
|
||
|
||
GSCRegs Dcb.b 10,0 ; The GSC reg save/restore area.
|
||
|
||
|
||
WITH DBLiteVidPrivates,VDPageInfo,DBGrayTblRec
|
||
|
||
|
||
**********************************************************************
|
||
*
|
||
* DBLiteVidOpen allocates private storage for the device in the AuxDCE and locks
|
||
* it down for perpetuity. Also, install the simulated interrupt handler and
|
||
* start it going.
|
||
*
|
||
* Entry: A0 = param block pointer
|
||
* A1 = AuxDCE pointer
|
||
*
|
||
* Locals: A3 = pointer to private storage
|
||
*
|
||
**********************************************************************
|
||
|
||
DBLiteVidOpen
|
||
|
||
;
|
||
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
|
||
; a pointer to it in A3.
|
||
;
|
||
|
||
MOVEQ #DBLiteVidPrivSize,D0 ; get size of parameters
|
||
_ResrvMem ,SYS ; make room as low as possible
|
||
MOVEQ #DBLiteVidPrivSize,D0 ; get size of parameters
|
||
_NewHandle ,SYS,CLEAR ; get some memory for private storage
|
||
BNE.S @OpError1 ; => return an error in open
|
||
MOVE.L A0,dCtlStorage(A1) ; save returned handle in AuxDCE
|
||
_HLock ; and lock it down forever (this includes a Time Mgr QElem)
|
||
MOVE.L (A0),D0 ; get a 32-bit clean pointerÉ
|
||
_StripAddress ; Éto our privates into A3
|
||
MOVEA.L D0,A3
|
||
|
||
;
|
||
; Remember the VDAC (GSC) and framebuffer base addresses since theyÕre fairly painful to look up.
|
||
;
|
||
With ProductInfo,DecoderInfo,VideoInfo
|
||
|
||
Move.l UnivInfoPtr,A0 ; Get a pointer to the universal data.
|
||
Move.l A0,-(Sp) ; Save it temporarily on the stack.
|
||
Adda.l DecoderInfoPtr(A0),A0 ; Point to the base address table.
|
||
Move.l VDACAddr(A0),saveGSCAddr(A3) ; Save pointer to GSC (ÒVDACÓ).
|
||
|
||
Move.l (Sp)+,A0 ; Point back at the universal data.
|
||
Adda.l VideoInfoPtr(A0),A0 ; Point to the VideoInfo record. <H3>
|
||
Move.l VRAMLogAddr32(A0),saveBaseAddr(A3) ; Save pointer to the framebuffer base.
|
||
|
||
Endwith
|
||
|
||
; The Niagra board does not support a real interrupt for doing VBLs,
|
||
; so we simulate them by using a Time Manager task that is set at 60.14742 Hz.
|
||
; While the DBLite board -does- support GSC interrupts, we found we had problems
|
||
; with cursor breakup at the top of the screen, so we now use a Time Manager
|
||
; task as well.
|
||
|
||
LEA TimeManagerIH,A0 ; get a pointer to the interrupt simulation timer task code
|
||
MOVE.L A0,tmAddr+TTask(A3) ; put it in the time task
|
||
LEA TTask(A3),A0 ; get a pointer to the timer queue element
|
||
Move.l #'eada',(A0) ; Put in the magic signature to prevent VM from deferring us.
|
||
_InsXTime ; Install the task (fixed frequency). <H6>
|
||
|
||
BSR DBLiteEnableVGuts ; do it
|
||
BNE.S @OpError2
|
||
|
||
; Attempt to re-open the Backlight driver because it might have been closed <H11>
|
||
; if someone (AUX?) closed us and then tried to reopen us prior to |
|
||
; rebooting. Currently, this call will fail the first time thru v
|
||
; 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 DBLiteBackLite,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! <H11>
|
||
;
|
||
MOVEQ #noErr,D0 ; no error
|
||
RTS
|
||
|
||
@OpError2 MOVE.L dCtlStorage(A1),A0 ; get the private storage back
|
||
_DisposHandle ; release the driver private storage
|
||
@OpError1 MOVEQ #OpenErr,D0 ; say can't open driver
|
||
RTS
|
||
|
||
|
||
**********************************************************************
|
||
*
|
||
* 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
|
||
*
|
||
**********************************************************************
|
||
|
||
DBLiteVidClose
|
||
|
||
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 DBLiteBackLite,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 screen.
|
||
;
|
||
Movea.l saveGSCAddr(A3),A0 ; Point to the GSC base address.
|
||
Bclr #GSCBlankCtl,GSCGrayScale(A0) ; Blank video.
|
||
|
||
; Disable cursor interrupts.
|
||
;
|
||
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
|
||
|
||
; Disable fixed-clut table if necessary.
|
||
;
|
||
Move.l saveFixedCLUT(A3),D0 ; If we havenÕt loaded our fixed-entry CLUT,
|
||
Beq.s @EndFixed ; then just go on.
|
||
Move.l D0,A0 ; Otherwise, dispose of it.
|
||
_DisposPtr
|
||
@EndFixed
|
||
|
||
; Dispose of private storage.
|
||
;
|
||
MOVE.L dCtlStorage(A1),A0 ; Dispose of the private storage
|
||
_DisposHandle ;
|
||
|
||
MOVEQ #noErr,D0 ; no error
|
||
RTS ; and return
|
||
|
||
|
||
**********************************************************************
|
||
*
|
||
* Video Driver Control Call Handler. There are ten calls:
|
||
*
|
||
* (0) Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr);
|
||
* (1) KillIO
|
||
* (2) SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr);
|
||
* (3) SetEntries ( Table: Ptr; Start,Count : integer );
|
||
* (4) SetGamma ( Table : Ptr );
|
||
* (5) GrayPage (page);
|
||
* (6) SetGray (csMode = 0 for color, 1 for gray)
|
||
* (7) SetInterrupt ( csMode = 0 for enable, 1 for disable)
|
||
* (8) DirectSetEntries (not implemented)
|
||
* (9) SetDefaultMode
|
||
*
|
||
* Entry: A0 = param block pointer
|
||
* A1 = AuxDCE pointer
|
||
* Uses: A2 = ptr to cs parameters (ie. A2 <- csParam(A0))
|
||
* A3 = scratch (doesn't need to be preserved)
|
||
* A4 = scratch (must be preserved)
|
||
* D0-D3 = scratch (don't need to be preserved)
|
||
*
|
||
* Exit: D0 = error code
|
||
*
|
||
**********************************************************************
|
||
|
||
DBLiteVidCtl
|
||
LEA @ctlJumpTbl-2,A4 ; point to the Control dispatch table
|
||
MOVEQ #controlErr,D0 ; default error if it's a bad opcode
|
||
BRA.S DBLiteCSCommon ; jump to common Control/Status code
|
||
|
||
DC.W (@StdctlJumpTblEnd-2-@ctlJumpTbl)/2; highest control call we support
|
||
@ctlJumpTbl DC.W DBLiteVidReset-@ctlJumpTbl ; $00 => VidReset
|
||
DC.W DBLiteKillIO-@ctlJumpTbl ; $01 => KillIO
|
||
DC.W DBLiteSetVidMode-@ctlJumpTbl ; $02 => SetVidMode
|
||
DC.W DBLiteSetEntries-@ctlJumpTbl ; $03 => SetEntries ¥¥¥ MacsBug Hack ¥¥¥
|
||
DC.W DBLiteCSDone-@ctlJumpTbl ; $04 => SetGamma (not needed)
|
||
DC.W DBLiteGrayPage-@ctlJumpTbl ; $05 => GrayPage
|
||
DC.W DBLiteCSDone-@ctlJumpTbl ; $06 => SetGray (not needed)
|
||
DC.W DBLiteSetInterrupt-@ctlJumpTbl ; $07 => SetInterrupt
|
||
* DC.W DBLiteCSDone-@ctlJumpTbl ; $08 => DirectSetEntries (not needed)
|
||
* DC.W DBLiteCSDone-@ctlJumpTbl ; $09 => SetDefaultMode (not needed)
|
||
@StdctlJumpTblEnd
|
||
DC.W cscSleepWake,DBLiteSetSleepWake-@ctlJumpTbl ; SleepWake
|
||
DC.W 0 ; end-of-table marker
|
||
|
||
**********************************************************************
|
||
*
|
||
* Video Driver Status Call Handler. Right now there are ten calls:
|
||
*
|
||
* (0) Error
|
||
* (1) Error
|
||
* (2) GetMode
|
||
* (3) GetEntries
|
||
* (4) GetPage
|
||
* (5) GetPageBase
|
||
* (6) GetGray
|
||
* (7) GetInterrupt
|
||
* (8) GetGamma
|
||
* (9) GetDefaultMode
|
||
*
|
||
* Entry: A0 = param block
|
||
* 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
|
||
*
|
||
**********************************************************************
|
||
|
||
DBLiteVidStatus
|
||
LEA @statJmpTbl-2,A4 ; point to the Status dispatch table
|
||
MOVEQ #statusErr,D0 ; default error if it's a bad opcode
|
||
BRA.S DBLiteCSCommon
|
||
|
||
DC.W (@StdstatJmpTblEnd-2-@statJmpTbl)/2; highest status call we support
|
||
@statJmpTbl DC.W DBLiteCSDone-@statJmpTbl ; $00 => Error
|
||
DC.W DBLiteCSDone-@statJmpTbl ; $01 => Error
|
||
DC.W DBLiteGetMode-@statJmpTbl ; $02 => GetMode
|
||
DC.W DBLiteGetEntries-@statJmpTbl ; $03 => GetEntries
|
||
DC.W DBLiteGetPage-@statJmpTbl ; $04 => GetPage
|
||
DC.W DBLiteGetPageBase-@statJmpTbl ; $05 => GetPageBase
|
||
DC.W DBLiteGetGray-@statJmpTbl ; $06 => GetGray
|
||
DC.W DBLiteGetInterrupt-@statJmpTbl ; $07 => GetInterrupt
|
||
DC.W DBLiteCSDone-@statJmpTbl ; $08 => GetGamma (not needed)
|
||
DC.W DBLiteGetDefaultMode-@statJmpTbl; $09 => GetDefaultMode
|
||
@StdstatJmpTblEnd
|
||
DC.W cscSleepWake,DBLiteGetSleepWake-@statJmpTbl ; SleepWake
|
||
DC.W 0 ; end-of-table marker
|
||
|
||
DBLiteCSCommon
|
||
MOVE.W csCode(A0),D1 ; get the opcode
|
||
MOVE.W (A4)+,D2 ; get size of StdTable <H11>
|
||
CMP.W D2,D1 ; IF inStdRange THEN |
|
||
BLS.S @DoCall ; use StdTable and Do CntrCall v
|
||
MOVE.W D2,D3 ; Get end of StdTable
|
||
SUBQ.W #1,D3 ; adjust for first element in extended tbl <H12>
|
||
@Loop ADDQ.W #2,D3 ; Increment counter
|
||
MOVE.W (A4,D3.W*2),D2 ; Get routine code
|
||
BEQ.S @BadCode ; End of list ReachedÉ Bad Code
|
||
CMP.W D2,D1 ; IF csCode == TableCode THEN
|
||
BNE.S @Loop ; Use Extended Range
|
||
|
||
MOVE.W D3,D1 ; Use new index
|
||
ADDQ.W #1,D1 ; increment it for proper table entry <H11>
|
||
|
||
@DoCall MOVEA.L csParam(A0),A2 ; point to parameters
|
||
MOVE.L D0,-(SP) ; save the error code
|
||
MOVEA.L dCtlStorage(A1),A3 ; point to our storage
|
||
MOVE.L (A3),D0 ; and de-reference the handle
|
||
_StripAddress ; make sure the pointer is 32-bit clean
|
||
MOVEA.L D0,A3 ; save the 32-bit clean pointer
|
||
MOVE.L (SP)+,D0 ; restore error code
|
||
MOVEM.L A0-A3,-(SP) ; save exit registers
|
||
MOVE.W (A4,D1.W*2),D1 ; get the relative offset to the routine
|
||
JSR 0(A4,D1.W) ; Go do it
|
||
MOVEM.L (SP)+,A0-A3 ; restore exit registers.
|
||
|
||
Move.w csCode(A0),D1 ; Get the routine selector.
|
||
Cmpi.w #cscSetMode,D1 ; If itÕs the SetMode routine,
|
||
Beq.s @EndBlnkChk ; then donÕt unblank the display.
|
||
Cmpi.w #cscSleepWake,D1 ; If itÕs the Sleep/Wake routine,
|
||
Beq.s @EndBlnkChk ; then donÕt unblank the display.
|
||
Bclr #InBlanking,GFlags(A3) ; Say that we want the screen unblanked now.
|
||
Bsr DBLiteBlankCtl ; And do it.
|
||
@EndBlnkChk
|
||
@BadCode BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
|
||
BNE.S DBLiteCSDone ; -> yes, it's an immediate call, so just exit
|
||
MOVE.L jIODone,-(SP) ; otherwise exit thru IODone
|
||
DBLiteCSDone
|
||
RTS
|
||
|
||
**********************************************************************
|
||
*
|
||
* Control Routines
|
||
*
|
||
**********************************************************************
|
||
|
||
|
||
DBLiteVidReset
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Reset the card to its default
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.W #FirstVidMode,csMode(A2) ; return default mode
|
||
MOVE.W #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
|
||
MOVEQ #0,D1 ; get default depth in D1 (#firstVidMode-#firstVidMode)
|
||
MOVEQ #0,D0 ; get page in D0
|
||
MOVE.W D0,csPage(A2) ; return the page
|
||
|
||
BSR DBLiteSetDepth ; set the depth from D1 (also grays the screen)
|
||
|
||
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
||
DBLiteKillIO
|
||
MOVEQ #NoErr,D0
|
||
RTS
|
||
|
||
|
||
DBLiteSetVidMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Set the card to the specified mode and page. Only page zero is
|
||
; possible, so we need to check that the request was OK.
|
||
;
|
||
; If the card is already set to the specified mode, then do nothing.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Move.w csMode(A2),D1 ; D1 = mode.
|
||
BSR DBLiteChkMode ; check mode and convert
|
||
BHI.S @BadParam ; => not a valid mode
|
||
|
||
Tst.w csPage(A2) ; only page zero is valid
|
||
BNE.S @BadParam ; => not a valid page
|
||
|
||
; Only set if the mode has changed.
|
||
|
||
Move.w csMode(A2),D2 ; get the mode spID (D1 has the zero-base mode)
|
||
Cmp.w saveMode(A3),D2 ; has the mode changed?
|
||
Beq.s @ModeOK ; if not, just return the baseAddr
|
||
|
||
; Remember the newly requested mode, and switch depths with our utility.
|
||
|
||
Bset #InBlanking,GFlags(A3) ; Say that we want the screen to be blanked.
|
||
Bsr DBLiteBlankCtl ; And go do it.
|
||
|
||
Move.w D2,saveMode(A3) ; remember requested mode
|
||
Bsr DBLiteSetDepth ; switch depths
|
||
|
||
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.
|
||
|
||
@ModeOK Move.l saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
||
MOVEQ #NoErr,D0
|
||
@BadParam RTS
|
||
|
||
|
||
DBLiteSetEntries
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Since DBLite has no color table, thereÕs nothing to do here. We
|
||
; donÕt do this in the dispatcher above so that the BlankShading
|
||
; works with MacsBug around.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Moveq #controlErr,D0 ; Say that we donÕt do entries.
|
||
Rts ; And vamoose.
|
||
|
||
DBLiteSetGamma
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Since DBLite has no color table, there's no opportunity to set the
|
||
; gamma correction in this hardware. Return a bad result but
|
||
; do it up above in the control dispatcher, since it saves a few bytes.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
|
||
DBLiteGrayPage
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Clear the specified page in the current mode to gray
|
||
;
|
||
; A1 = Ptr to AuxDCE
|
||
; A2 = Ptr to cs parameter record
|
||
; A3 = Ptr to private storage
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Move.w saveMode(A3),D1 ; D1 = mode
|
||
Bsr DBLiteChkMode ; convert mode to depth in D1
|
||
BHI.S @BadParam ; => not a valid depth
|
||
|
||
TST.W csPage(A2) ; Is it requesting page zero?
|
||
BNE.S @BadParam ; -> nope
|
||
|
||
BSR DBLiteGrayScreen ; paint the screen gray
|
||
MOVEQ #NoErr,D0
|
||
@BadParam RTS
|
||
|
||
|
||
DBLiteSetGray
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Since DBLite has no color table, there's no opportunity to set
|
||
; luminence mapping in this hardware. Return a bad result but
|
||
; do it up above in the control dispatcher, since it saves a few bytes.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
|
||
DBLiteSetInterrupt
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Enable (csMode = 0) or disable (csMode = 1) VBL interrupts
|
||
;
|
||
; As a future performance enhancement, interrupts on the card can be
|
||
; disabled or enabled from software. For instance, if the cursor is
|
||
; not on a screen, and there is nothing in the Slot Interrupt Queue
|
||
; for that device, interrupts may be disabled reducing interrupt
|
||
; overhead for the system.
|
||
;
|
||
; The slot interrupt queue element is always allocated by the Open call.
|
||
; This routine just inserts and removes it from the slot interrupt task queue.
|
||
;
|
||
; A1 = Ptr to AuxDCE
|
||
; A2 = Ptr to cs parameter record
|
||
; A3 = Ptr to private storage
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
|
||
Tst.b csMode(A2) ; Check to see which way weÕre going.
|
||
Bne.s DBLiteDisableVGuts ; If non-zero, disabling.
|
||
Bra.s DBLiteEnableVGuts ; Otherwise, enabling.
|
||
|
||
DBLiteDisableVGuts
|
||
Move.w #-1,IntDisableFlag(A3) ; Remember that weÕre disabling things.
|
||
MOVEQ #NoErr,D0
|
||
RTS
|
||
|
||
|
||
DBLiteEnableVGuts
|
||
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 #kDBLiteVBLTime,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 ;
|
||
Moveq #NoErr,D0 ; say weÕre okay
|
||
RTS ; return home
|
||
|
||
|
||
DBLiteSetDefaultMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Since DBLite has no sRsrc families, just return bad result
|
||
; but do it up above in the control dispatcher, since it saves a
|
||
; few bytes.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
|
||
DBLiteSetSleepWake
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; SleepWake <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
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
; Check to see if we even need to be here or notÉ
|
||
;
|
||
Moveq #controlErr,D0 ; Assume weÕll fail for now.
|
||
|
||
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 not already awake, then
|
||
Bne.s @DoWakeup ; go do the wakeup code.
|
||
Rts ; Otherwise, somethingÕs wrong.
|
||
|
||
@DoWakeup Bsr DBLiteRestoreState ; Go restore the state of the world.
|
||
Bsr DBLiteEnableVGuts ; Turn cursor interrupts back on.
|
||
Moveq #noErr,D0 ; And returnÉ
|
||
Rts ; Éhappy.
|
||
|
||
@ChkSleep Btst #IsSleeping,GFlags(A3) ; If weÕre not already sleeping, then
|
||
Beq.s @DoSleep ; go do the sleep code.
|
||
Rts ; Otherwise, somethingÕs wrong.
|
||
|
||
@DoSleep Bsr DBLiteDisableVGuts ; Turn off cursor interrupts for good measure.
|
||
Bsr DBLiteSaveState ; Save the state of the world.
|
||
Moveq #noErr,D0 ; And returnÉ
|
||
Rts ; Éhappy.
|
||
|
||
|
||
**********************************************************************
|
||
*
|
||
* Status Routines
|
||
*
|
||
**********************************************************************
|
||
|
||
|
||
DBLiteGetMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the current mode
|
||
;
|
||
; Inputs : A2 = pointer to csParams
|
||
; A3 = pointer to private storage
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Tst.w saveMode(A3) ; If saveMode has been set,
|
||
Bne.s @ModeOK ; then just go on.
|
||
Move.w #FirstVidMode,saveMode(A3) ; Otherwise, just set it to 1bpp (non-GSC case).
|
||
|
||
@ModeOK MOVE.W saveMode(A3),csMode(A2) ; return the mode
|
||
CLR.W csPage(A2) ; return the page number
|
||
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; and the base address
|
||
|
||
MOVEQ #NoErr,D0
|
||
RTS
|
||
|
||
|
||
DBLiteGetEntries
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; 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 DBLite 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 @GEDone ; then just exit
|
||
MOVE.L D1,D0
|
||
_StripAddress ; Otherwise, make table pointer 32-bit clean
|
||
MOVE.L D0,D3 ; and save it for later
|
||
|
||
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, <H8>
|
||
Bne.s @ModeOK ; then go on.
|
||
Move.b #FirstVidMode,D0 ; Otherwise, assume 1bpp (non-GSC case).
|
||
|
||
@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.S @GEDone ; -> yes, bail
|
||
|
||
EndWith
|
||
|
||
; Calculate the index rangeÉ
|
||
;
|
||
@GEStart MOVEQ #statusErr,D0
|
||
Move.l D3,A0 ; get pointer to input table.
|
||
|
||
Move.w saveNumFixedEntries(A3),D3 ; Get number of entries to check against.
|
||
|
||
Move.w csCount(A2),D4 ; Get the number of entries to change,
|
||
Bmi @GEDone ; and hike if itÕs out of range.
|
||
Cmp.w D3,D4 ; If D4-D3 > 0 (count - range > 0),
|
||
Bhi @GEDone ; 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 @GEDone ; 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.
|
||
|
||
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
|
||
|
||
MOVEQ #NoErr,D0 ; success
|
||
@GEDone RTS
|
||
|
||
|
||
DBLiteGetPage
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the number of pages in the specified mode.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Move.w csMode(A2),D1 ; get the mode
|
||
BSR.S DBLiteChkMode ; is this mode OK?
|
||
BHI.S @BadMode ; => not a valid mode
|
||
|
||
MOVE.W #defPagesLCD,csPage(A2) ; return page count
|
||
MOVEQ #NoErr,D0
|
||
@BadMode RTS
|
||
|
||
|
||
DBLiteGetPageBase
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the base address for the specified page in the current mode
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
TST.W csPage(A2) ; are we returning page zero info?
|
||
BNE.S @BadPage ; => no, just return
|
||
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
||
MOVEQ #NoErr,D0
|
||
@BadPage RTS
|
||
|
||
|
||
DBLiteGetGray
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; No CLUT, but this routine always returns a non-zero value (1)
|
||
; to indicate that gray mode is on (forever).
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Move.b #1,csMode(A2) ; Say that gray mode is on.
|
||
Moveq #noErr,D0
|
||
Rts
|
||
|
||
|
||
DBLiteGetInterrupt
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return a boolean in csMode, set true if VBL interrupts are disabled
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Tst.w IntDisableFlag(A3) ; If the interrupt state is enabled,
|
||
Beq.s @IsOn ; then say so.
|
||
Move.b #1,csMode(A2) ; Otherwise, return disabled.
|
||
Bra.s @Done ; And leave.
|
||
|
||
@IsOn Clr.b csMode(A2) ; Return enabled state.
|
||
|
||
@Done Moveq #noErr,D0 ; Return noErr.
|
||
Rts ; And leave.
|
||
|
||
|
||
DBLiteGetGamma
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; No CLUT, so this routine returns an status error. It's implemented
|
||
; in the Status dispatch table above.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
|
||
DBLiteGetDefaultMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Read the card default mode from slot pRAM.
|
||
;
|
||
; A1 = Ptr to AuxDCE
|
||
; A2 = Ptr to cs parameter record
|
||
; A3 = Ptr to private storage
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
; For most video drivers, we look in pRAM to see what the last
|
||
; configuration set was. However, for DBLite, we just need
|
||
; to return our current functional sRsrc ID (i.e., there are
|
||
; no family modes here).
|
||
|
||
MOVE.B dCtlSlotID(A1),csMode(A2) ; return the result
|
||
MOVEQ #NoErr,D0
|
||
RTS
|
||
|
||
|
||
DBLiteGetSleepWake
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; GetSleepWake
|
||
;
|
||
; 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 <- 0 = sleep, non-zero = wake
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
Btst #IsSleeping,GFlags(A3) ; Test the sleep/wake flag.
|
||
Seq csMode(A2) ; Return result.
|
||
Moveq #noErr,D0 ; Vamoose.
|
||
Rts
|
||
|
||
;=====================================================================
|
||
;
|
||
; Utilities
|
||
;
|
||
;=====================================================================
|
||
|
||
|
||
DBLiteChkMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; 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
|
||
;
|
||
; Returns BHI if mode is invalid.
|
||
;
|
||
|
||
SUBI.W #FirstVidMode,D1 ; make mode zero-based.
|
||
CMPI.W #ThirdVidMode-FirstVidMode,D1 ; valid mode values are 0-2
|
||
RTS
|
||
|
||
|
||
DBLiteSetDepth
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; SetDepth
|
||
;
|
||
; Set the requested frame buffer depth.
|
||
;
|
||
; D1 = spID of the depth - FirstVidMode
|
||
; A1 = AuxDCEPtr
|
||
; A2 = param block pointer
|
||
; A3 = dCtlStorage pointer
|
||
;
|
||
; All registers are preserved.
|
||
|
||
Movem.l D0/D2/A0,-(Sp) ; Save work registers.
|
||
|
||
; Raise the interrupt level to level 2 so that VBL and timer tasks will not run
|
||
|
||
Move.w SR,-(Sp) ; Get the status register on stack. <H11>
|
||
Moveq #7,D0 ; Get mask into D0. |
|
||
And.b (SP),D0 ; Get the interrupt level. v
|
||
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 <H11>
|
||
@OK
|
||
Move.l saveGSCAddr(A3),A0 ; Get the GSC base address.
|
||
Move.b GSCGrayScale(A0),D0 ; Get the current value. <H13>
|
||
|
||
; The GSC has a problem where DSACK may not happen after the last register access. If <H11>
|
||
; we delay 2 frame times (approx. 32ms), then the GSC corrects itself, otherwise we will |
|
||
; get a bus timeout bus error waiting for DSACK. This problem is particularly annoying v
|
||
; because the GSC may decide to give DSACK at sometime later which would really screw us up.
|
||
|
||
Moveq #33,D2 ; Initialize loop for 33 milliseconds
|
||
@DelayLoop Swap D2 ; get low word for millisecond delay
|
||
Move.w TimeDbra,D2 ; how many spins???
|
||
@mSecDelay Dbra D2,@mSecDelay ; Delay 1 millisecond
|
||
Swap D2 ; Get out loop counter
|
||
Dbra D2,@DelayLoop ; spin <H11>
|
||
|
||
Bfins D1,D0{GSCLevelBits,GSCLevelWidth} ; Switch depths.
|
||
Move.b D0,GSCGrayScale(A0) ;
|
||
|
||
MOVEQ #7,D2 ; mask off the display ID, <H10>
|
||
AND.B GSCPanelID(A0),D2 ; <H10>
|
||
|
||
Cmpi.b #5,D2 ; If this isnÕt the Dart FSTN panel,
|
||
Bne.s @NotDartFSTN ; then just go on.
|
||
Move.b @polyAdj(D1),GSCPolyAdj(A0) ; Otherwise, set the m and n values.
|
||
Bra.s @NotTFT ; Skip TFT code.
|
||
@NotDartFSTN
|
||
Cmpi.b #1,D2 ; If this isnÕt the TFT display,
|
||
Bne.s @NotTFT ; then just go on.
|
||
Move.b #$0B,GSCDiag2(A0) ; Invert VRAM data.
|
||
Clr.b GSCPanelAdj(A0) ; Invert LCD.
|
||
@NotTFT
|
||
MULU #3,D2 ; multiply panel ID by 3 to use as a table index, <H10>
|
||
ADD.W D1,D2 ; and add in the bit depth <H10>
|
||
|
||
MOVE.B @refreshReg(D2),GSCRefreshRate(A0) ; adjust the display refresh rate <H10>
|
||
MOVE.B @skewReg(D2),GSCPanelSkew(A0) ; and the panel skew <H10>
|
||
|
||
Move.w (Sp)+,SR ; restore interrupt level
|
||
Movem.l (Sp)+,D0/D2/A0 ; Restore work registers.
|
||
Rts
|
||
|
||
|
||
; values for the refresh register based on the display mode
|
||
;
|
||
; 1-bit 2-bit 4-bit
|
||
|
||
@refreshReg DC.B 5, 3, 3 ; ID=0: TFT 1-bit <H10>
|
||
DC.B 5, 3, 3 ; ID=1: TFT 3-bit <H10>
|
||
DC.B 5, 3, 3 ; ID=2: TFT 4-bit <H10>
|
||
DC.B 5, 3, 3 ; ID=3: TFT (unassigned) <H10>
|
||
DC.B 5, 3, 3 ; ID=4: STN (unassigned) <H10>
|
||
DC.B 5, 3, 3 ; ID=5: STN - Tim <H10>
|
||
DC.B 5, 3, 3 ; ID=6: STN - DBLite <H10>
|
||
DC.B 5, 3, 3 ; ID=7: no display <H10>
|
||
|
||
; values for the skew register based on the display mode
|
||
;
|
||
; 1-bit 2-bit 4-bit
|
||
|
||
@skewReg DC.B 160, 64, 64 ; ID=0: TFT 1-bit (60Hz, 87Hz, 87Hz) <H10>
|
||
DC.B 240, 240, 240 ; ID=1: TFT 3-bit (70Hz, 70Hz, 70Hz) <H20>
|
||
DC.B 255, 128, 64 ; ID=2: TFT 4-bit (68Hz, 87Hz, 87Hz) <H10>
|
||
DC.B 255, 128, 64 ; ID=3: TFT (unassigned) (60Hz, 87Hz, 87Hz) <H10>
|
||
DC.B 160, 64, 64 ; ID=4: STN (unassigned) (60Hz, 87Hz, 87Hz) <H10>
|
||
DC.B 161, 65, 4 ; ID=5: STN - Tim (??Hz, ??Hz, ??Hz) <H20>
|
||
DC.B 156, 64, 3 ; ID=6: STN - DBLite (62Hz, 87Hz, 120Hz) <H17>
|
||
DC.B 160, 64, 64 ; ID=7: no display <H10>
|
||
|
||
; values for the m&n polyadj register based on the display mode
|
||
;
|
||
|
||
@polyAdj Dc.b 99, 130, 99 ; ID=5: STN - TIM <H20>
|
||
|
||
DC.B 00 ;padding ??? PN
|
||
DBLiteGrayScreen
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Fill the screen with a 50% dithered gray pattern.
|
||
;
|
||
; D1 = spID of screen depth - FirstVidMode
|
||
; A3 = driver private storage
|
||
;
|
||
; All registers are preserved.
|
||
;
|
||
|
||
MOVEM.L D0/D2/D3/A0-A1,-(SP) ; save work registers
|
||
|
||
Moveq #true32b,D0 ; Set up to flip into 32-bit mode.
|
||
_SwapMMUMode ; Flip.
|
||
Move.b D0,-(Sp) ; Save previous mode.
|
||
|
||
Lea DBLiteGrayTbl,A0 ; Point to the table of graying data,
|
||
Lea (A0,D1*DBGrayTblSize),A0; and load the right entry. <H3>
|
||
|
||
MOVE.L saveBaseAddr(A3),A1 ; Get the frame buffer base address.
|
||
MOVE.W grayTblCol(A0),D0 ; Get the number of rows to do.
|
||
Move.l grayTblPat(A0),D3 ; Get the bit-pattern.
|
||
|
||
@NxtRow MOVE.W grayTblRow(A0),D2 ; Get the number of longwords per row.
|
||
@NxtLong MOVE.L D3,(A1)+ ; Write grayÉ
|
||
DBRA D2,@NxtLong ; Éfor each scanline.
|
||
NOT.L D3 ; Invert pattern on the next row.
|
||
DBRA D0,@NxtRow ; Loop until done.
|
||
|
||
Move.b (Sp)+,D0 ; Restore previous addressing mode.
|
||
_SwapMMUMode
|
||
|
||
MOVEM.L (SP)+,D0/D2/D3/A0-A1 ; restore registers
|
||
RTS
|
||
|
||
DBLiteSaveState
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; 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
|
||
;
|
||
|
||
|
||
Bset #IsSleeping,GFlags(A3) ; Remember that weÕve been asked to sleep.
|
||
|
||
Movem.l D0-D1/A0/A4,-(Sp) ; Save some working registers.
|
||
|
||
Movea.l saveGSCAddr(A3),A0 ; Point to the GSC base address.
|
||
Addq #GSCPanelControl,A0 ; Point to the first reg to save.
|
||
|
||
Lea GSCRegs,A4 ; Point to the register holder area.
|
||
|
||
; Save the state of the RegistersÉ
|
||
;
|
||
MOVE.W (A0)+,(A4)+ ; panel control, panel setup
|
||
MOVEQ #$7F,D0 ; mask off the interrupt status bit
|
||
AND.B (A0)+,D0 ; in the gray scale register
|
||
MOVE.B D0,(A4)+ ; gray scale
|
||
MOVE.L (A0)+,(A4)+ ; polynomial adjust, panel adjust, ACDCLK, refresh rate
|
||
MOVE.W (A0)+,(A4)+ ; blank shade, panel skew
|
||
|
||
; Gray the VRAMÉ
|
||
;
|
||
Move.w saveMode(A3),D1 ; Get the current mode.
|
||
Subi.w #FirstVidMode,D1 ; Normalize it.
|
||
Bsr DBLiteGrayScreen ; Gray the screen.
|
||
|
||
Movem.l (Sp)+,D0-D1/A0/A4 ; Restore the working registers.
|
||
Rts
|
||
|
||
DBLiteRestoreState
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; 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
|
||
;
|
||
|
||
Movem.l D0-D1/A0/A4,-(Sp) ; Save some working registers.
|
||
|
||
Movea.l saveGSCAddr(A3),A0 ; Point to the GSC base address.
|
||
Addq #GSCPanelControl,A0 ; Point to the first reg to restore.
|
||
|
||
Lea GSCRegs,A4 ; Point to the register holder area.
|
||
|
||
; Save the state of the RegistersÉ
|
||
;
|
||
MOVE.W (A4)+,(A0)+ ; panel control, panel setup
|
||
MOVE.B #(1<<7),(A0) ; reset the VBL interrupt pin
|
||
MOVE.B (A4)+,(A0)+ ; gray scale
|
||
MOVE.L (A4)+,(A0)+ ; polynomial adjust, panel adjust, ACDCLK, refresh rate
|
||
MOVE.W (A4)+,(A0) ; blank shade, panel skew
|
||
|
||
Movea.l saveGSCAddr(A3),A0 ; Repoint to the GSC base address.
|
||
MOVEQ #7,D1 ; Panel IDs are only 3-bits wide.
|
||
And.b GSCPanelID(A0),D1 ; Get the PanelID.
|
||
Cmpi.b #1,D1 ; If this isnÕt the TFT display,
|
||
Bne.s @NotTFT ; then just go on.
|
||
Move.b #$0B,GSCDiag2(A0) ; Otherwise, invert VRAM data.
|
||
Bra.s @EndRegs ;
|
||
@NotTFT
|
||
Move.b #$03,GSCDiag2(A0) ; Who knows?
|
||
@EndRegs
|
||
|
||
; Gray the VRAMÉ
|
||
;
|
||
Move.w saveMode(A3),D1 ; Get the current mode.
|
||
Subi.w #FirstVidMode,D1 ; Normalize it.
|
||
Bsr DBLiteGrayScreen ; Gray the screen.
|
||
|
||
Movem.l (Sp)+,D0-D1/A0/A4 ; Restore the working registers.
|
||
Bclr #IsSleeping,GFlags(A3) ; Remember that weÕre no longer asleep.
|
||
Rts
|
||
|
||
DBLiteBlankCtl
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; 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. Ugh!
|
||
;
|
||
; 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 saveGSCAddr(A3),A0 ; Point to the GSC base address.
|
||
Btst #InBlanking,GFlags(A3) ; If weÕre supposed to be blanking the LCD,
|
||
Bne.s @BlankIt ; then do it.
|
||
Bset #GSCBlankCtl,GSCGrayScale(A0) ; Otherwise, unblank it.
|
||
Bra.s @EndBlank ; Move along.
|
||
@BlankIt Bclr #GSCBlankCtl,GSCGrayScale(A0) ; Blank the screen.
|
||
@EndBlank
|
||
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 Time Manager Task Built-In Video
|
||
;-----------------------------------------------------------------------------
|
||
;
|
||
; The new time manager sets A1 to point to the TTask block on entry
|
||
;
|
||
|
||
TimeManagerIH ; <H6> Thru next <H6>
|
||
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) <3> djw
|
||
|
||
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 <3> djw
|
||
MOVE.L #kDBLiteVBLTime,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 <H6>
|
||
|
||
|
||
ENDWITH
|
||
END
|
||
|