
;TRIDENT.INC - Writen by Erik Olbrys
;    History:
;        July 14, 1991 - first release
;        22 Nov 1992 - Adapted by Knight Software for protected mode
;        25 Nov 1994 - Added virtual cmds, fixed scan line length
;
;	            *WARNING* I don't have a trident card, so the
;                             new code has not been tested. 
;			      Use at your own risk. 
;
;----------------------------------------------------------------------
;Determine what sort of card is out there
;Assumed: DS=data segment
;Entry:   N/A
;Return:  AL=status error result (see error list in SDATA.INC)
;Destroy: AX

DetectCard PROC NEAR
	PUSH    ES                      ;check if this is a Trident
	PUSH	SI
	PUSH	DI
	PUSH	DX
	PUSH	CX
	PUSH    BX

	MOV	BX,DS:[SEGA000]		;init video segment/selector
	MOV	DS:[VideoSegment],BX
	MOV	BX,0FFFFH		 ;Init bank select reg
	MOV	DS:[PixelSegment],BX
	MOV	BX,0
	MOV	DS:[VidMode],BX
	MOV	DS:[VidMemSize],BX
	MOV	DS:[NumberModes],BX
	MOV	AL,grOK
	MOV	DS:[ModeErrorFlag],AL 	;preclear error flag

noncr:	cli
  	mov     dx,3c4h                 ;Test for Trident
	mov     al,0bh
	out     dx,al           ;out(3c4,0b)
	inc     dl
	in      al,dx           ;al:=inp(3c5)
	sti
	cmp     al,06h
	ja      notri           ;if al>6
	cmp     al,2
	jb      notri           ;if al<2

	JAE     @IsTrident              ;yup, so go init it

notri:	MOV	BX,320		        ;set default scan line length
	MOV	DS:[ScanLineBytes],BX
	MOV	DI,OFFSET VGABankSelect ;allow select mode 13H only
	MOV	DS:[BankSelectProc],DI
	MOV	DI,OFFSET VGA320x200Init
	MOV	DS:[InitDisplayProc],DI
	MOV	BX,64		        ;default window granularity = 64K
	MOV	DS:[WinGran],BX
	MOV	BX,0
	MOV	DS:[ModeSelect],BL      ;def select mode
	MOV	AX,1
	MOV	DS:[NumberModes],AX     ;set number modes to 1
	MOV	DS:[DisplayPages],AL	;set display pages to 1

	MOV	AX,1A00H
	INT	10H			;check if VGA type display
	CMP	AL,1AH
	JNZ	@NotVGA
	MOV	DS:[DisplayType],BX
	CMP	BL,6			;allow MCGA or VGA support
	JC	@NotVGA
	CMP	BL,0AH			;but not digital MCGA
	JZ	@NotVGA

	MOV	DI,OFFSET VGAcard
	MOV	DS:[CardNamePtr],DI
	JMP	SHORT @DetectExit

@IsTrident:
	cli
	MOV	DX,3C4H			;update videm memory size
	MOV	AL,1FH
	OUT	DX,AL
	INC	DX
	IN	AL,DX
	sti
	MOV	AH,AL
	AND	AX,0700H	
	MOV	DS:[VidMemSize],AX

	MOV     AX,MaxModes                ;set number modes available
	MOV     DS:[NumberModes],AX
	MOV     BX,OFFSET TRBankSelect     ;set bank select proc pointer
	MOV     DS:[BankSelectProc],BX

	MOV     AL,DS:[ModeSelect]
	AND     AX,7
	MOV     BX,OFFSET TRModeProcTable  ;set display init proc pointer
	ADD     BX,AX
	ADD     BX,AX
	MOV     BX,CS:[BX]
	MOV     DS:[InitDisplayProc],BX
	MOV     BX,OFFSET TRname
	MOV     DS:[CardNamePtr],BX        ;set up pointer to card name
	MOV     BX,64
	MOV     DS:[WinGran],BX            ;set window granularity
	JMP	@DetectExit

;Couldn't find VGA/MCGA, so just error out
@NotVGA:
	MOV	AL,grNoInitGraph 	   ;mark as mode error
	MOV	DS:[ModeErrorFlag],AL
	MOV	DI,OFFSET DummyCard
	MOV	DS:[CardNamePtr],DI
	MOV	BYTE PTR DS:[ModeSelect],0 ;force mode to 0
@DetectExit:
	MOV	AL,DS:[ModeErrorFlag]	   ;return error status
	POP     BX
	POP	CX
	POP	DX
	POP	DI
	POP	SI
	POP     ES
	RET
DetectCard ENDP

MaxModes EQU 5  ;max number modes available for Trident

TRModeProcTable:
	DW      TRvga320x200Init        ;table of init proc ptrs
	DW      TRvga640x400Init        ;for the various modes
	DW      TRvga640x480Init 
	DW      TRvga800x600Init 
	DW      TRvga1024x768Init       ;Requires 1 meg ram

	DW      VGA320x200Init          ;dummy excess mode selects
	DW      VGA320x200Init          ;to fill out to 8 positions
	DW      VGA320x200Init 

TRname:
	DB 8            ;name length
	DB ' Trident',0 ;Card name preceeded with space
			;and taged with a zero
VGAcard	 DB 8
	 DB 'VGA/MCGA',0	;default VGA id

;----------------------------------------------------------------------
;Select TRvga320x200 mode operation
;Assumed: DS=data segment
;Entry:   N/A
;Return:  Correct display mode selected
;Destroy: AX

TRvga320x200Init PROC NEAR
	PUSH	DX
	PUSH	BX
	mov     ax,13h
	INT     10H                     ;call BIOS to set the mode
	MOV	AX,64	;64K mem req for 320x200
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	POP	DX
	XOR     AX,AX
	RET
TRvga320x200Init ENDP

;----------------------------------------------------------------------
;Select TRvga640x400 mode operation
;Assumed: DS=data segment
;Entry:   N/A
;Return:  Correct display mode selected
;Destroy: AX

TRvga640x400Init PROC NEAR
	PUSH	DX
	PUSH	BX
	mov     ax,5ch
	INT     10H                     ;call BIOS to set the mode
	MOV	AX,250	;250K mem req for 640x400
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	POP	DX
	XOR     AX,AX
	RET
TRvga640x400Init ENDP

;----------------------------------------------------------------------
;Select TRvga640x480 mode operation
;Assumed: DS=data segment
;Entry:   N/A
;Return:  Correct display mode selected
;Destroy: AX

TRvga640x480Init PROC NEAR
	PUSH	DX
	PUSH	BX
	mov     ax,5dh
	INT     10H                     ;call BIOS to set the mode
	MOV	AX,300	;300K mem req for 640x480
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	POP	DX
	XOR     AX,AX
	RET
TRvga640x480Init ENDP

;----------------------------------------------------------------------
;Select TRvga800x600 mode operation
;Assumed: DS=data segment
;Entry:   N/A
;Return:  Correct display mode selected
;Destroy: AX

TRvga800x600Init PROC NEAR
	PUSH	DX
	PUSH	BX
	mov     ax, 5eh
	INT     10H                     ;call BIOS to set the mode
	MOV	AX,469	;469K mem req for 800x600
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	POP	DX
	XOR     AX,AX
	RET
TRvga800x600Init ENDP

;----------------------------------------------------------------------
;Select TRvga1024x768 mode operation
;Assumed: DS=data segment
;Entry:   N/A
;Return:  Correct display mode selected
;Destroy: AX

TRvga1024x768Init PROC NEAR
	PUSH	DX
	PUSH	BX
	mov     ax,62h
	INT     10H                     ;call BIOS to set the mode
	MOV	AX,768	;768K mem req for 1024x768
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	POP	DX
	XOR     AX,AX
	RET
TRvga1024x768Init ENDP


;----------------------------------------------------------------------

SetPageCount PROC NEAR
	PUSH	DX
	PUSH	BX
	MOV	BX,AX
	MOV	AX,DS:[VidMemSize]
	OR	AX,AX
	JZ	@SetPgCntExit
	MOV	DX,0
	DIV	BX
@SetPgCntExit:
	MOV	DS:[DisplayPages],AL
	POP	BX
	POP	DX
	RET
SetPageCount ENDP


;----------------------------------------------------------------------
;Trident Bank select routines - We assume that full memory is
;available if you try to access it.
;Assumed: DS=data segment
;Entry:   DX = Bank to select
;Return:  Display Bank is selected
;Destroy: nothing

TRBankSelect PROC NEAR
	PUSH	DX
	PUSH	AX
	cli
	mov     DS:[curbank],dx
	mov     dx,3ceh                 ;set pagesize to 64k
	mov     al,6
	out     dx,al           ;out(03ce,6)
	inc     dl
	in      al,dx           ;inp
	dec     dl
	or      al,4
	mov     ah,al
	mov     al,6
	out     dx,ax           ;out(03ce,6)

	mov     dl,0c4h                 ;switch to BPS mode
	mov     al,0bh
	out     dx,al           ;out(03ce,0b)
	inc     dl
	in      al,dx           ;inp
	dec     dl

	mov     ah,byte ptr DS:[curbank]
	xor     ah,2
	mov     dx,3c4h
	mov     al,0eh
	out     dx,ax           ;out(03c4,0e)
	sti
	POP	AX
	POP	DX
	ret
TRBankSelect ENDP


;----------------------------------------------------------------------
;select new display screen position in virtual display memory
;Assume:  DS = data segment          ** WARNING: THIS HAS NOT BEEN TESTED **
;Enter:   [ScreenOfsX] = X offset
;         [ScreenOfsY] = Y offset
;Return:  new display position is selected 
;Destory: None

SetScreenPos PROC NEAR
	RET		;Sorry, I haven't tested the trident 
			;virtual display. Here is what the code
			;looks like. comment out the return
			;if you want to try it.


	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CLI

	MOV	DX,DS:[ScanLineBytes]
	MOV	AX,DS:[ScreenOfsY] ;convert X/Y to memory position
	MUL	DX
	ADD	AX,DS:[ScreenOfsX]
	ADC	DX,0	;DX:AX = memory position
	MOV	BL,AL
	AND	BL,3	;BL=horizontal pel offset
	SHL	BL,1
	SHR	DX,1
	RCR	AX,1
	SHR	DX,1
	RCR	AX,1
	MOV	CX,AX	;CX = CRTC offset
	MOV	BH,DL
	AND	BH,01H  ;BH = CRTC page
	SHL	BH,1	
	SHL	BH,1	
	SHL	BH,1	
	SHL	BH,1	
	SHL	BH,1
	OR	BH,80H

	MOV	DX,3D4H      ;set CRTC base addr
	MOV	AL,0CH
	MOV	AH,CH
	OUT	DX,AX	     ;CX=adr0-15
	MOV	AL,0DH
	MOV	AH,CL
	OUT	DX,AL

	MOV	DX,3DAH
	IN	AL,DX
	MOV	DX,3C0H	     ;set horz pel pan reg
	MOV	AL,13H+20H
	OUT	DX,AL
	MOV	AL,BL
	OUT	DX,AL

	MOV	DX,3C4H      ;sequencer
	MOV	AL,01EH      ;256k bank select
	OUT	DX,AL
	INC	DX           ;point to data
	IN	AL,DX
	AND	AL,0DFH      ;clear out bank select 
	OR	AL,BH	     ;AH=new select
	OUT	DX,AL        ;set bank select 
	STI

	POP	DX
	POP	CX
	POP	BX
	POP	AX
	RET
SetScreenPos ENDP


;----------------------------------------------------------------------
;select new scan line length. This updates the virtual screen.
;You must call SetGraphMode() after using this function
;in order to initialize the BGI and graph unit variables to the new 
;display parameters. Note that this will change the display resolution.
;Assume:  DS = data segment
;Enter:   AX = New scan line length to use
;Return:  ScanLineBytes is updated is valid
;Destory: None

SetScanLineLength PROC NEAR
	RET		;Sorry, I haven't tested the trident 
			;virtual display. Here is what the code
			;looks like. comment out the return
			;if you want to try it.


	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	DX
	TEST	AX,0C000H	        ;invalid selection if high bits set
	JNZ	@SetScanLenError
	MOV	BX,DS:[StatBlockPtr]
	MOV	BX,DS:[BX].status.Defxres
	INC	BX
	CMP	AX,BX			;can't make line smaller than screen
	JNC	@SetScanLenLimit
	MOV	AX,BX
@SetScanLenLimit:
	TEST	AX,7
	JZ	@SetScanLenAdj
	ADD	AX,8
@SetScanLenAdj:
	SHR	AX,1
	SHR	AX,1
	SHR	AX,1
	MOV	CX,AX

	MOV	DX,3D4H
	MOV	AL,13H
	MOV	AH,CL
	OUT	DX,AX

	SHL	CX,1
	SHL	CX,1
	SHL	CX,1
	MOV	DS:[ScanLineBytes],CX
	MOV	DS:[VirtualWidth],CX
	MOV	BX,DS:[StatBlockPtr]
	MOV	DS:[BX].status.VirtualScanBytes,CX

	MOV	AX,DS:[BX].status.Defyres
	INC	AX
	MOV	DX,DS:[VidMemSize]	;compute total virtual scan lines
	OR	DX,DX
	JZ	@SetScanLenLines
	OR	CX,CX
	JZ	@SetScanLenLines
	MOV	AX,1024
	MUL	DX
	DIV	CX
@SetScanLenLines:
	MOV	DS:[VirtualHeight],AX

	MOV	byte ptr [VirtualFlag],1 ;1=virtual IS supported
@SetScanLenError:
	MOV	BX,0FFFFH		 ;Init bank select reg
	MOV	DS:[PixelSegment],BX
	POP	DX
	POP	CX
	POP	BX
	POP	AX
	RET
SetScanLineLength ENDP


;----------------------------------------------------------------------
;get current scan line length. 
;Assume:  DS = data segment
;Enter:   nothing
;Return:  ScanLineLength is updated
;Destory: None

UpdateScanLineLength PROC NEAR
	PUSH	AX
	PUSH	DX
	CLI
	MOV	DX,3D4H
	MOV	AL,13H
	OUT	DX,AL
	INC	DX
	IN	AL,DX
	STI
	SHL	AX,1
	SHL	AX,1
	SHL	AX,1
	MOV	DS:[ScanLineBytes],AX
	POP	DX
	POP	AX
	RET
UpdateScanLineLength ENDP
