
;V7INIT.INC - Copyright 1991-1994  Knight Software
;    History:
;         17 May 1991 - first release
;         27 Nov 1994 - added virtual functions
;
;----------------------------------------------------------------------
;Determine what sort of card is out there
;Assume:  DS = data segment
;Entry:   N/A
;Return: AL=status error result (see error list in SDATA.INC)
;External Updates: 
;	VideoSegment, NumberModes, VidMemSize, DisplayType 
;       ModeErrorFlag, ScanLineBytes, DisplayPages
;       BankSelectProc, InitDisplayProc, CardNamePtr
;Destroy: AH

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

	MOV	DX,3C4H		;enable extended reg access
	MOV	AL,6
	MOV	AH,0EAH
	OUT	DX,AX

	MOV	BX,DS:[SEGA000]
	MOV	DS:[VideoSegment],BX    ;init Video Segment/selector info
	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

	MOV	BX,0
	MOV	AX,6F00H
	INT	10H
	CMP	BX,'V7'
	JNZ	@NotV7			;not V7 card

@IsVideoSeven:
	MOV	AX,6F07H
	INT	10H			;get memory size
	AND	AX,7F00H		;strip garbage
	MOV	DS:[VidMemSize],AX	;save size in KB

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

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

;Couldn't find V7, so fall back on standard VGA
@NotV7:
	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

;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 Video Seven

V7ModeProcTable:
	DW	v7VGA320x200Init  ;table of init proc ptrs
	DW	V7vga640x400Init  ;for the various modes
	DW	V7vga640x480Init 
	DW	V7vga800x600Init 
	DW	V7vga1024x768Init ;(V7 VRAM II only)

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

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

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

V7vga320x200Init PROC NEAR
	PUSH	BX
	MOV	AX,0013H
	INT	10H	;call BIOS to set the mode
	MOV	AX,64	;64K mem req for 320x200
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	XOR	AX,AX	;always ret zero
	RET
V7vga320x200Init ENDP

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

V7vga640x400Init PROC NEAR
	PUSH	BX
	MOV	AX,6F05H
	MOV	BL,66H	;get graph mode to select
	INT	10H	;call BIOS to set the mode
	MOV	AX,250	;250K mem req for 640x400
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	XOR	AX,AX	;always ret zero
	RET
V7vga640x400Init ENDP

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

V7vga640x480Init PROC NEAR
	PUSH	BX
	MOV	AX,6F05H
	MOV	BL,67h	;get graph mode to select
	INT	10H	;call BIOS to set the mode
	MOV	AX,300	;300K mem req for 640X480
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	XOR	AX,AX	;always ret zero
	RET
V7vga640x480Init ENDP

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

V7vga800x600Init PROC NEAR
	PUSH	BX
	MOV	AX,6F05H
	MOV	BL,69h	;get graph mode to select
	INT	10H	;call BIOS to set the mode
	MOV	AX,469	;469K mem req for 800x600
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	XOR	AX,AX	;always ret zero
	RET
V7vga800x600Init ENDP

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

V7vga1024x768Init PROC NEAR	;@@@ Is this the right select code? @@@
	PUSH	BX
	MOV	AX,6F05H
	MOV	BL,6Ah	;get graph mode to select
	INT	10H	;call BIOS to set the mode
	MOV	AX,768	;768K mem req for 1024x768
	CALL	SetPageCount
	CALL	UpdateScanLineLength
	POP	BX
	XOR	AX,AX	;always ret zero
	RET
V7vga1024x768Init 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


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

V7BankSelect PROC NEAR
	PUSH	AX
	PUSH	BX
	PUSH	DX
	CLI
	MOV 	BL,DL
	AND 	BL,1        ;bl=extended page select
	MOV 	AH,DL
	AND 	AH,2
	SHL 	AH,1
	SHL	AH,1
	SHL	AH,1
	SHL	AH,1        ;ah = page select bit
	AND	DL,0CH
	MOV	BH,DL
	SHR	DL,1
	SHR	DL,1
	OR	BH,DL        ;bh=256k bank select
	MOV	DX,3CCH
	IN	AL,DX        ;get misc output reg
	AND	AL,0FFH-20H  ;clear page select bit
	OR	AL,AH        ;set page select bit
	MOV	DX,3C2H      ;write misc output register
	OUT	DX,AL
	MOV	DX,3C4H      ;sequencer
	MOV	AL,0F9H      ;extended page select register
	MOV	AH,BL        ;extended page select value
	OUT	DX,AX
	MOV	AL,0F6H      ;256k bank select
	OUT	DX,AL
	INC	DX           ;point to data
	IN	AL,DX
	AND	AL,0F0H      ;clear out bank select banks
	OR	AL,BH        ;set bank select banks
	OUT	DX,AL
	STI
	POP	DX
	POP	BX
	POP	AX
	RET
V7BankSelect ENDP


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

SetScreenPos PROC NEAR
	RET		;Sorry, V7 just doesn't seem to work with
			;the virtual display. Here is what the code
			;looks like, but the display screws up.


	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CLI

	MOV	DX,3C4H	;enable extended reg access
	MOV	AL,6
	MOV	AH,0EAH
	OUT	DX,AX

	MOV	DX,3DAH
	IN	AL,DX
	MOV	DX,3C0H	     ;get scan pel size
	MOV	AL,10H+20H
	OUT	DX,AL
	INC	DX
	IN	AL,DX
	MOV	CX,0300H     ;1 bit pels
	TEST	AL,40H
	JZ	@SSP2
	MOV	CX,0601H     ;2 bit pels
@SSP2:	MOV	DX,3D4H
	MOV	AL,13H	     ;get physical scan line length
	OUT	DX,AL
	INC	DX
	IN	AL,DX
	STI
	XOR	AH,AH
	SHL	AX,1
	SHL	AX,1
	SHL	AX,1
	MOV	DX,DS:[ScreenOfsY] ;convert X/Y to memory position
	MUL	DX
	ADD	AX,DS:[ScreenOfsX]
	ADC	DX,0	;DX:AX = memory position

	MOV	BL,AL	;BL=horizontal pel offset
	SHL	BL,CL
	AND	BL,CH
	SHR	DX,1
	RCR	AX,1
	SHR	DX,1
	RCR	AX,1
	MOV	CX,AX	;CX = CRTC offset
	MOV	BH,DL
	AND	BH,03H  ;BH = CRTC page

@SSP5:	MOV	DX,3DAH	     ;sync to vertical interrupt
	IN	AL,DX	     ;to prevent flashing
	TEST	AL,8
	JZ	@SSP5
@SSP6:	MOV	DX,3DAH
	IN	AL,DX
	TEST	AL,8
	JNZ	@SSP6

	CLI
	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,AX

	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

	SHL	BH,1
	SHL	BH,1
	SHL	BH,1
	SHL	BH,1
	MOV	DX,3C4H      ;sequencer
	MOV	AL,0F6H      ;256k bank select
	OUT	DX,AL
	INC	DX           ;point to data
	IN	AL,DX
	AND	AL,0CFH      ;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, V7 just doesn't seem to work with
			;the virtual display. Here is what the code
			;looks like, but the display screws up.


	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
	INC	AX
	AND	AX,0FEH
	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

