sys7.1-doc-wip/DeclData/DeclVideo/Tim/TimDriver.a
2019-07-27 22:37:48 +08:00

897 lines
30 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: TimDriver.a
;
; Contains: This file contains the video driver for use by the Macintosh
; OS for the Jaws (TIM) hardware.
;
; Written by: David A. Fung/Mike Puckett
;
; Copyright: © 1990-91 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM3> 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
; <SM2> 11/2/92 kc Don't include SonicEqu.a.
; <1> 10/6/92 GDW New location for ROMLink tool.
; <SM4> 09-03-92 jmp (jmp,H2) Corrected .s vs. non-.s branches and odd-alignment
; problems.
; <1> 3/30/92 JSM first checked in
; <10> 6/10/91 djw Add NeedsGoodBye Kiss csCode to Control, to close driver
; <9> 6/5/91 jmp In VidOpen, I now try to re-open the Backlight driver, because
; it might have been closed. In VidClose, I now close the
; Backlight driver and gray the screen; this is to support a new &
; improved method of restarting and shutting donw the system
; (i.e., to prevent desktop persistence on restart).
; <8> 5/22/91 jmp Code Review changes: For consistency, did a StripAddress on
; VidOpens copy of the privates; eliminated the redundant clears
; and checks for the the driver copy of the fixed-entry clut; and
; replaced #0s with #noErrs where appropriate.
; <7> 5/15/91 jmp SetInterrupt wasnt checking the input value (supposed to be
; either 0 or 1), but instead was just looking at D0; so, it would
; either enable (0) or disable (1), depending on whether D0.w was
; non-zero or not. GetInterrupt returned -1.w (instead of 1.b)
; for the disabled state, so some test tools were getting
; confused; so, I now just return 1.b when interrupts are
; disabled.
; <6> 5/10/91 jmp Made the GrayScreen code more universal (for things like
; DB-Lite) by swapping into 32-bit mode prior to accessing the
; framebuffer.
; <5> 5/10/91 jmp Fixed a bug in GetEntries where A0 was not loaded properly.
; Made GetEntries 32-bit clean. GetEntries was trashing A1, so
; async calls were failing (i.e., jumping thru IODone requires A1
; to be pointing to the AuxDCE). Indexed GetEntries didnt work
; at because I was checking for index vs. sequential off A3
; instead of A2! Made the Control & Status dispatchers 32-bit
; clean. SaveMode was never being set up! From the code review:
; Changed the TimeMgr task to micro-second base and fixed
; frequency at approximately 60.15Hz; eliminated SetEntries &
; SetDefaultMode and fixed GetDefaultMode.
; <4> 4/17/91 jmp Updated various comments, and cleaned up the fixed-device
; support.
; <3> 4/15/91 djw Fix trashed register bug in interrupt handler, Enabled fixed
; depth code in Open.
; <2> 2/15/91 jmp Started looking into making TIM a fixed device, but need to get
; working properly -- commented out for now. Also, need to look
; at VidClose for last VBL problem.
; <1> 12/8/90 HJR First time for Terror.
; <3> 9/13/90 MSH Waimea is gone, long live TIM
; <2> 4/19/90 DAF Correct header (I almost got it right...)
; <1> 4/19/90 DAF Added WaimeaDriver.a for the first time
;
;-------------------------------------------------------------------
; Mod History :
;
; 17Apr90 DAF New today (spawned from ElsieDriver.a)
;
;-------------------------------------------------------------------
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 '_sTimDriver'
BLANKS ON
STRING ASIS
MACHINE MC68020
kTIMVBLTime EQU -16626 ; 60.14742 Hz using the microsecond timer.
; This is device storage which is stored in the dCtlStorage field of the AuxDCE.
TIMVidPrivates RECORD 0
saveBaseAddr DS.L 1 ; the screen base address
saveFixedCLUT DS.L 1 ; pointer to fixed-entry CLUT
saveNumFixedEntries DS.W 1 ; number of entries in fixed CLUT (zero based)
saveMode DS.W 1 ; the current mode setting
GFlags DS.W 1 ; flags word
TTask DS.B tmXQSize ; extended time manager task block
IntDisableFlag DS.W 1 ; this word is non-zero when the VBL interrupt
; simulator is disabled
TIMVidPrivSize EQU *
ENDR
LTimDriver MAIN EXPORT
;-------------------------------------------------------------------
; Video Driver Header
;-------------------------------------------------------------------
;
TIMDrvr DC.W $5C00 ; ctl,status,needsLock,needsGoodBye
DC.W 0,0,0 ; not an ornament
; Entry point offset table
DC.W TIMVidOpen-TIMDrvr ; open routine
DC.W TIMDrvr-TIMDrvr ; no prime
DC.W TIMVidCtl-TIMDrvr ; control
DC.W TIMVidStatus-TIMDrvr ; status
DC.W TIMVidClose-TIMDrvr ; close
STRING Pascal
TIMVidTitle DC.B '.Display_Video_Apple_TIM'
STRING ASIS
ALIGN 2 ; make sure we're word aligned
DC.W CurTimDrvrVersion ; version
;
; 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 cant really turn TIMs video off,
; we must simulate it by turning off the backlighting and writing
; white (because its 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 drivers open routine. And, for this reason,
; when we close the backlight driver, we do NOT remove its DCE,
; and do we dont 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
TIMBackLite Dc.b '.Backlight' ; Name of Backlight Driver for TIM.
String Asis
Align 2
**********************************************************************
*
* TIMVidOpen 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
*
**********************************************************************
WITH VDPageInfo,TIMVidPrivates,spBlock
TIMVidOpen
;
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
; a pointer to it in A3.
;
MOVEQ #TIMVidPrivSize,D0 ; get size of parameters
_ResrvMem ,SYS ; make room as low as possible
MOVEQ #TIMVidPrivSize,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 (this includes a Time Mgr QElem)
MOVE.L (A0),A3 ; get a pointer to it
MOVE.L (A0),D0 ; Get a 32-bit clean pointer
_StripAddress ; to our privates into A3.
Move.l D0,A3
MOVE.L dCtlDevBase(A1),saveBaseAddr(A3) ; save the screen base address
;
; TIM doesn't have a normal slot interrupt handler since the LCD doesn't really interrupt! We simulate
; the interrupt with a timer task that goes off at 60.14742 Hz.
LEA TIMBeginIH,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).
; Note that IntDisableFlag is clear from the NewHandle above which “enables” the interrupt.
BSR TIMEnableVGuts ; turn on and prime the interrupt simulator
; For doing GetEntries, we need to get our fixed-entry CLUT from the Slot Manager.
;
With spBlock
Suba #spBlockSize,Sp ; Make an SpBlock on the stack and
Move.l Sp,A0 ; get a pointer to it in A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Get the slotnumber.
Move.b dCtlSlotID(A1),spID(A0) ; Get the spID of video sRsrc.
Clr.b spExtDev(A0) ;
_sRsrcInfo ; Try to get the spsPointer.
Bne.s @OpError2 ; Were dead if this fails.
Move.b #firstVidMode,spID(A0) ; Look for our mode entry.
_sFindStruct ; If we dont find it, then
Bne.s @OpError2 ; were dead.
Move.b #mTable,spID(A0) ; Get our fixed-entry CLUT.
_sGetBlock ; If we dont get it, then
Bne.s @OpError2 ; were dead.
Move.l spResult(A0),A0 ; Get ptr to fixed-entry CLUT
Move.w ctSize(A0),saveNumFixedEntries(A3) ; Save the number of entries.
Lea ctTable(A0),A0 ; Get ptr to table, and
Move.l A0,saveFixedCLUT(A3) ; save it.
Adda #spBlockSize,Sp ; restore stack
EndWith
; Theres only one vidMode, so save it now because SetMode doesnt need to.
;
Move.w #firstVidMode,saveMode(A3)
; 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.
;
Sub.w #ioQElSize,Sp ; Get a param block on the stack.
Move.l Sp,A0 ; Point to it.
Lea TIMBackLite,A1 ; Get pointer to Backlight driver name.
Move.l A1,ioFileName(A0) ; Load it.
_Open ; Open the driver.
Add.w #ioQElSize,Sp ; Restore the stack.
; All done!
;
@AllDone MOVEQ #noErr,D0 ; no error
@EndOpen RTS ; return
@OpError2 ADDA #spBlockSize,SP ; release the spBlock
LEA TTask(A3),A0 ; get the time manager task block
_RmvTime ; remove this element from the queue
MOVE.L dCtlStorage(A1),A0 ; get the private storage back
_DisposHandle
@OpError1 MOVE.L #OpenErr,D0 ; say can't open driver
BRA.S @EndOpen
ENDWITH
**********************************************************************
*
* Video Driver Control Call Handler. There are ten calls:
*
* (-1) GoodBye kiss <t10>
* (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
*
**********************************************************************
;
; Decode the call
;
TIMVidCtl
MOVEM.L A0/A1,-(SP) ; Preserve exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
MOVE.W csCode(A0),D0 ; get the opCode
ADDQ.W #1,D0 ; offset opCode by 1 <t10>
CMP.W #10,D0 ; IF csCode NOT IN [0..10] THEN <t10>
BHI.S TIMCtlBad ; Error, csCode out of bounds
MOVE.W TIMCtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine
JMP TIMCtlJumpTbl(PC,D0.W) ; GOTO the proper routine
TIMCtlJumpTbl
DC.W TIMGoodBye-TIMCtlJumpTbl ; $FF => NeedGoodBye Kiss <t10>
DC.W TIMVidReset-TIMCtlJumpTbl ; $00 => VidReset
DC.W TIMCtlGood-TIMCtlJumpTbl ; $01 => KillIO
DC.W TIMSetVidMode-TIMCtlJumpTbl ; $02 => SetVidMode
DC.W TIMCtlBad-TIMCtlJumpTbl ; $03 => SetEntries (not needed)
DC.W TIMCtlBad-TIMCtlJumpTbl ; $04 => SetGamma (not needed)
DC.W TIMGrayPage-TIMCtlJumpTbl ; $05 => GrayPage
DC.W TIMCtlBad-TIMCtlJumpTbl ; $06 => SetGray (not needed)
DC.W TIMSetInterrupt-TIMCtlJumpTbl ; $07 => SetInterrupt
DC.W TIMCtlBad-TIMCtlJumpTbl ; $08 => DirectSetEntries (not needed)
DC.W TIMCtlBad-TIMCtlJumpTbl ; $09 => SetDefaultMode (not needed)
TIMCtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
BRA.S TIMCtlDone ; and return
TIMCtlGood MOVEQ #noErr,D0 ; return no error
TIMCtlDone MOVEM.L (SP)+,A0/A1 ; Restore exit registers.
BRA TIMExitDrvr
TIMGoodBye ; <t10>
;---------------------------------------------------------------------
;
; Upon the GoodBye Kiss, close the video driver
;
;---------------------------------------------------------------------
BSR.S TIMVidClose ; make the driver close call
BRA.S TIMCtlGood ; => no error
TIMVidReset
;---------------------------------------------------------------------
;
; Reset the card to its default
;
;---------------------------------------------------------------------
WITH VDPageInfo,TIMVidPrivates
MOVE #FirstVidMode,csMode(A2) ; return default mode
MOVE #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
CLR.W csPage(A2) ; return page zero
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
BSR TIMGrayScreen ; paint the screen gray
BRA.S TIMCtlGood ; => no error
ENDWITH
TIMSetVidMode
;---------------------------------------------------------------------
;
; Set the card to the specified mode and page. If it's not 1-bit
; mode, page zero, then return an error
;
; If the card is already set to the specified mode, then do nothing.
;
;---------------------------------------------------------------------
WITH VDPageInfo,TIMVidPrivates
CMP.W #FirstVidMode,csMode(A2) ; is it one-bit (the first and only)
BNE.S TIMCtlBad ; => not a valid mode
TST.W csPage(A2) ; it is page zero?
BNE.S TIMCtlBad ; => not a valid page
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
BRA.S TIMCtlGood ; => return no error
ENDWITH
TIMSetEntries
;---------------------------------------------------------------------
;
; Since TIM has no color table, theres nothing do here. Return a ctl
; bad result (but do it up above in the control dispatcher, since it
; saves a few bytes.
;
;---------------------------------------------------------------------
TIMSetGamma
;---------------------------------------------------------------------
;
; Since TIM has no color table, there's no opportunity to set the
; gamma correction in this hardware. Return a ctl bad result (but
; do it up above in the control dispatcher, since it saves a few bytes.
;
;---------------------------------------------------------------------
TIMGrayPage
;---------------------------------------------------------------------
;
; 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
;
;---------------------------------------------------------------------
WITH VDPageInfo,TIMVidPrivates
TST.W csPage(A2) ; Is it requesting page zero?
BNE.S TIMCtlBad
BSR TIMGrayScreen ; paint the screen gray
BRA.S TIMCtlGood ; => return no error
ENDWITH
TIMSetGray
;---------------------------------------------------------------------
;
; Since TIM has no color table, there's no opportunity to set
; luminence mapping in this hardware. Return a ctl bad result (but
; do it up above in the control dispatcher, since it saves a few bytes.
;
;---------------------------------------------------------------------
TIMSetInterrupt
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = non-zero) VBL interrupts
;
; As a future performance enhancement, interrupts on the card can be
; disabled or enabled from software. For instance, if the cursor is
; not on a screen, and there is nothing in the Slot Interrupt Queue
; for that device, interrupts may be disabled reducing interrupt
; overhead for the system.
;
; The slot interrupt queue element is always allocated by the Open call.
; This routine just inserts and removes it from the slot interrupt task queue.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH VDPageInfo,TIMVidPrivates
Move.b csMode(A2),D0 ; get mode
Ext.w D0 ; extend for word-sized flag
MOVE.W D0,IntDisableFlag(A3) ; save it
BNE.S TIMSIDone ; if disabling, setting the flag word is all that's needed
; if enabling interrupt simulator, then we need to prime the timer task
BSR.S TIMEnableVGuts ; call common code
TIMSIDone
BRA.S TIMCtlGood ; and go home
TIMEnableVGuts ;
MOVE.L A1,-(SP) ; jPrimeTime trashes A1 <3> djw
LEA TTask(A3),A0 ; get time task block in A0
MOVE.L #kTIMVBLTime,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 ; <3> djw
RTS ; return home
ENDWITH
TIMSetDefaultMode
;---------------------------------------------------------------------
;
; Since TIM only has one video sRsrc and its already set, just return
; a ctl bad result (but do it up above in the control dispatcher, since
; it saves a few bytes.
;
;---------------------------------------------------------------------
**********************************************************************
*
* 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
*
**********************************************************************
WITH TIMVidPrivates
TIMVidClose
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
; Shut off VBL 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
; Close the Backlight driver.
;
Sub.w #ioQElSize,Sp ; Get a param block on the stack.
Move.l Sp,A0 ; Point to it.
Lea TIMBackLite,A1 ; Get pointer to Backlight driver name.
Move.l A1,ioFileName(A0) ; Load it.
_Open ; Open driver to get the refNum.
Bne.s @SkipClose ; If open fails, dont try to close it.
_Close ; Otherwise, close it.
@SkipClose
Add.w #ioQElSize,Sp ; Restore the stack.
; Gray the screen.
;
Bsr TimGrayScreen ; Gray the screen.
; Dispose of all storage.
;
Move.l saveFixedCLUT(A3),A0 ; Dispose of our fixed-entry CLUT.
_DisposPtr
MOVE.L dCtlStorage(A1),A0 ; Dispose of the private storage
_DisposHandle ;
MOVEQ #noErr,D0 ; no error
RTS ; and return
ENDWITH
**********************************************************************
*
* 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
*
**********************************************************************
TIMVidStatus
MOVEM.L A0/A1,-(SP) ; Preserve exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
CMP.W #9,D0 ;IF csCode NOT IN [0..9] THEN
BHI.S TIMStatBad ; Error, csCode out of bounds.
MOVE.W TIMStatJumpTbl(PC,D0.W*2),D0 ;Get the relative offset to the routine.
JMP TIMStatJumpTbl(PC,D0.W) ;GOTO the proper routine.
TIMStatJumpTbl
DC.W TIMStatBad-TIMStatJumpTbl ;$00 => Error
DC.W TIMStatBad-TIMStatJumpTbl ;$01 => Error
DC.W TIMGetMode-TIMStatJumpTbl ;$02 => GetMode
DC.W TIMGetEntries-TIMStatJumpTbl ;$03 => GetEntries
DC.W TIMGetPage-TIMStatJumpTbl ;$04 => GetPage
DC.W TIMGetPageBase-TIMStatJumpTbl ;$05 => GetPageBase
DC.W TIMStatBad-TIMStatJumpTbl ;$06 => GetGray (not needed)
DC.W TIMGetInterrupt-TIMStatJumpTbl ;$07 => GetInterrupt
DC.W TIMStatBad-TIMStatJumpTbl ;$08 => GetGamma (not needed)
DC.W TIMGetDefaultMode-TIMStatJumpTbl ;$09 => GetDefaultMode
TIMStatBad MOVEQ #statusErr,D0 ; else say we don't do this one
BRA.S TIMStatDone ; and return
TIMStatGood MOVEQ #noErr,D0 ; return no error
TIMStatDone MOVEM.L (SP)+,A0/A1 ; Restore exit registers.
BRA TIMExitDrvr
TIMGetMode
;---------------------------------------------------------------------
;
; Return the current mode
;
; Inputs : A2 = pointer to csParams
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
WITH TIMVidPrivates,VDPageInfo
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
BRA.S TIMStatGood ; => return no error
ENDWITH
TIMGetEntries
;---------------------------------------------------------------------
;
; 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 : A2 = pointer to csParams
; A3 = pointer to privates
;
; For TIM the color table is fixed. So, well always return good values
; as long as there is a reasonable looking color table around.
;
; Idea: If were in indexed mode, well cycle thru the input
; table. While doing this, well ignore all entries
; whose value fields are out of range. For entries
; whose value field are in range, well return the
; appropriate rgb fields.
;
; If were in sequential mode, we just need to write out
; the number of entries we know about.
;
;---------------------------------------------------------------------
With TimVidPrivates
Move.l csTable(A2),D0 ; If we were handed a nil pointer,
Beq.s TIMStatBad ; then hike.
_StripAddress ; Otherwise, make it 32-bit clean.
Move.l D4,-(Sp) ; Save work register.
; Calculate the index range…
;
Move.w saveNumFixedEntries(A3),D3 ; Get number of entries to check against.
Move.w csCount(A2),D4 ; Get the number of entries to set,
Bmi.s @GEErr ; and hike if its out of range.
Cmp.w D3,D4 ; If D4-D3 > 0 (count > # of entries),
Bhi.s @GEErr ; then hike.
Move.w D4,D2 ; Otherwise, copy the count.
Move.l D0,A0 ; Get pointer to input table.
Cmp.w #indexEntries,csStart(A2) ; If table accesses are to be indexed,
Beq.s @GECom ; then go on.
Move.w D4,D1 ; Otherwise, sequence thru table from
Add.w csStart(A2),D2 ; csStart thru csCount entries.
; The following code is BAD, BAD, BAD! We should build our own table here so
; as to NOT mess up the users data. But all the previous Apple video drivers
; have done the same thing, so well continue the trend for now.
@TableLoop Move.w D2,value(A0,D1*colorSpecSize) ; Write the index into the table.
Subq #1,D2 ; 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.
Move.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 D4,@Repeat
Move.l (Sp)+,D4 ; Restore work register.
Bra.s TimStatGood ; Return noError.
@GEErr Move.l (Sp)+,D4 ; Restore work register.
Bra.s TimStatBad ; Return statError.
EndWith
TIMGetPage
;---------------------------------------------------------------------
;
; Return the number of pages in the specified mode.
;
;---------------------------------------------------------------------
WITH TIMVidPrivates,VDPageInfo
CMP.W #FirstVidMode,csMode(A2) ; this mode, or else
BNE TIMStatBad ; oh,oh
MOVE.W #OBMPagesLCD,csPage(A2) ; return page count
BRA TIMStatGood ; => return no error
ENDWITH
TIMGetPageBase
;---------------------------------------------------------------------
;
; Return the base address for the specified page in the current mode
;
;---------------------------------------------------------------------
WITH TIMVidPrivates,VDPageInfo
MOVE.W csPage(A2),D0 ; get the requested page
BNE TIMStatBad ; => no, just return
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
BRA TIMStatGood ; => return no error
ENDWITH
TIMGetGray
;---------------------------------------------------------------------
;
; No CLUT, so this routine returns an status error. It's implemented
; in the Status dispatch table above.
;
;---------------------------------------------------------------------
TIMGetInterrupt
;---------------------------------------------------------------------
;
; Return a boolean in csMode, set true if VBL interrupts are disabled
;
;---------------------------------------------------------------------
WITH TIMVidPrivates,VDPageInfo
TST.W IntDisableFlag(A3) ; test the interrupt state
BEQ.S @isOn ; if not on,
MOVE.B #1,csMode(A2) ; then return disabled state.
BRA TIMStatGood ;
@isOn
CLR.B csMode(A2) ; return enabled state
BRA TIMStatGood
ENDWITH
TIMGetGamma
;---------------------------------------------------------------------
;
; No CLUT, so this routine returns an status error. It's implemented
; in the Status dispatch table above.
;
;---------------------------------------------------------------------
TIMGetDefaultMode
;---------------------------------------------------------------------
;
; 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 TIM, there only one
; mode possible, so we just return that value here.
WITH VDPageInfo ; GDW1
MOVE.B dCtlSlotID(A1),csMode(A2) ; return the result
BRA TimStatGood ;
ENDWITH ; GDW1
;---------------------------------------------------------------------
;
; Exit from Control or Status.
;
; A0 = Ptr to param block.
; A1 = Ptr to AuxDCE.
; D0 = error code.
;
;---------------------------------------------------------------------
TIMExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
BEQ.S TIMGoIODone ; => no, not immediate
RTS ; otherwise, it was an immediate call
TIMGoIODone MOVE.L JIODone,-(Sp) ; Get the IODone address,
Rts ; and go there.
;=====================================================================
;
; Utilities
;
;=====================================================================
TIMGrayScreen
;---------------------------------------------------------------------
;
; Fill the screen with a 50% dithered gray pattern.
; A3 = driver private storage
;
; All registers are preserved
;
WITH TIMVidPrivates
MOVEM.L D0/D2/D3/A0/A1,-(SP) ; save all registers
Moveq #true32b,D0 ; Set up to flip into 32-bit mode.
_SwapMMUMode ; Flip.
Move.b D0,-(Sp) ; Save previous mode.
MOVE.L #OneBitGray,D3 ; get the one-bit gray pattern
MOVE.L saveBaseAddr(A3),A0 ; get the frame buffer base address
MOVE.W #defmBounds_BLCD-1,D0 ; get the # of rows
@NxtRow MOVE.W #(OBMLCDRB/4)-1,D2 ; get the # of longs/row
@NxtLong MOVE.L D3,(A0)+ ; write gray
DBRA D2,@NxtLong ; for each scanline
NOT.L D3 ; invert pattern on next row
DBRA D0,@NxtRow ; for each row
Move.b (Sp)+,D0 ; Restore previous addressing mode.
_SwapMMUMode
MOVEM.L (SP)+,D0/D2/D3/A0/A1 ; restore registers
RTS
ENDWITH
;-----------------------------------------------------------------------------
; The Interrupt handler for the TIM Built-In Video
;
; Since it doesn't make much sense for an LCD system to have all the
; interrupt related hardware that the CRT systems have since there
; really isn't a blanking interval anyway. On this machine we
; simulate the slot interrupt system with a timer task. We still
; call the slot VBL task queue so slot VBL tasks get called.
;-----------------------------------------------------------------------------
;
; The new time manager sets A1 to point to the TTask block on entry
;
TIMBeginIH
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 #kTIMVBLTime,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
END