; 800X600x256 for SuperVGA and VESA adapters
; loadable driver for The Graphics Engine
; Copyright (c) 1993 by Matthew Hildebrand

; Turbo Assembler syntax
; Portions by John Bridges

IDEAL
P286
MODEL LARGE


SCREEN_WIDE	EQU	800		; screen width in bytes & pixels
SCREEN_DEEP	EQU	600		; screen depth in pixels
SCREEN_SEG	EQU	0A000h		; base screen segment


	CODESEG
	ORG	0

	db	'GRAP'
	dw	initGraphics		; initGraphics
	dw	?
	dw      deInitGraphics		; deInitGraphics
	dw      ?
        dw      0			; putImage
        dw	?
        dw	0			; putImageInv
        dw	?
        dw	0			; getImage
        dw	?
        dw	putLine			; putLine
        dw	?
        dw	getLine			; getLine
        dw	?
        dw	0			; imageSize
        dw	?
	dw      putPixel		; putPixel
	dw	?
	dw	getPixel		; getPixel
	dw	?
	dw	0			; line
        dw      ?
        dw	horizLine		; horizLine
	dw	?
	dw	0			; drawRect
	dw	?
        dw      0			; filledRect
	dw	?
	dw	setPaletteReg		; setPaletteReg
	dw	?
        dw	getPaletteReg		; getPaletteReg
	dw	?
	dw	setBlockPalette		; setBlockPalette
	dw	?
        dw	getBlockPalette		; getBlockPalette
        dw	?
        dw	clearGraphics		; clearGraphics
        dw	?
	dw	SCREEN_WIDE-1		; maximum X-coordinate
	dw	SCREEN_DEEP-1		; maximum Y-coordinate
	dw	255			; maximum colour number (0-?)

	db	'The Graphics Engine -- Copyright (c) 1993 by Matthew Hildebrand'

inited		db	0
colourPalette	db	768	DUP(?)
lineOffs	dw	SCREEN_DEEP	DUP(?)
bankNum		dw	SCREEN_DEEP	DUP(?)
bankChanges	dw	SCREEN_DEEP	DUP(?)
curBank		dw	?
screenWide	dw	?

	LABEL	vesaBuf	WORD
vesaid		db	4 DUP(?)	; 4 signature bytes
vesaver		dw	?		; VESA version number
oemstr		dd	?		; Pointer to OEM string
capabil		db	4 DUP(?)	; Capabilities of the video environment
modelst		dd	?		; Pointer to supported Super VGA modes
vesashift	db	0		; number of bits to shift bank number left
	db	243	DUP(?)		; pad to 256 bytes

bankadr		dw	?
vga512		dw	?
vga1024		dw	?
cirrus		dw	?
everex		dw	?
paradise 	dw	?
tseng		dw	?
trident		dw	?
t8900		dw	?
ativga		dw	?
aheada		dw	?
aheadb		dw	?
oaktech		dw	?
video7		dw	?
chipstech 	dw	?
tseng4		dw	?
genoa		dw	?
ncr		dw	?
compaq		dw	?
vesa		dw	?
retval		dw	?		; first return value from whichvga()


MACRO	GETPALETTE
  push	di
  mov	cx,256
  mov	di,cs
  mov	es,di
  mov	di,OFFSET colourPalette
  cld
  mov	dx,3C7h				; set for right first pal reg
  xor	ax,ax
  out	dx,al
  mov	dx,3C9h
	@@GetPaletteLoop:
  in	al,dx
  shl	al,2
  stosb		; red
  in	al,dx
  shl	al,2
  stosb		; green
  in	al,dx
  shl	al,2
  stosb		; blue
  loop	@@GetPaletteLoop
  pop	di
ENDM

MACRO	SETPALETTE
  push	ds si
  mov	si,cs
  mov	ds,si
  mov	si,OFFSET colourPalette
  mov	cx,256
  cld
  mov	dx,3C8h				; set for right first pal reg
  xor	ax,ax
  out	dx,al
  inc	dx
	@@SetPaletteLoop:
  lodsb			; red
  shr	al,2
  jnc	@@L1
  cmp	al,63
  je	@@L1
  inc	al
  	@@L1:
  out	dx,al
  lodsb			; green
  shr	al,2
  jnc	@@L2
  cmp	al,63
  je	@@L2
  inc	al
  	@@L2:
  out	dx,al
  lodsb			; blue
  shr	al,2
  jnc	@@L3
  cmp	al,63
  je	@@L3
  inc	al
  	@@L3:
  out	dx,al
  loop	@@SetPaletteLoop
  pop	si ds
ENDM

MACRO	NEWBANK
  call	[bankadr]
ENDM


	PUBLIC C	initGraphics
PROC	C	initGraphics
  cmp	[inited],0
  je	@@NotInited
  call	setMode
  SETPALETTE
  mov	ax,1
  retf

  	@@NotInited:
  call	whichVGA
  or	ax,ax
  jz	@@NoDetect
  call	setMode

  push	si di
  mov	si,OFFSET lineOffs
  mov	di,OFFSET bankNum
  mov	cx,SCREEN_DEEP
  xor	bx,bx

	@@Loop1:
  mov	ax,[screenWide]			; calculate bank and offsets
  mul	bx				; for each line start
  mov	[cs:si],ax
  add	si,2
  mov	[cs:di],dx
  add	di,2
  inc	bx
  loop	@@Loop1

  mov	bx,1				; set flag table for bank change
  mov	cx,SCREEN_DEEP			; mid-line
  mov	si,OFFSET bankChanges
  mov	[word ptr cs:si],0
  add	si,2
  	@@Loop2:
  mov	ax,[screenWide]
  mul	bx
  mov	di,dx
  mov	ax,[screenWide]
  inc	bx
  mul	bx
  sub	ax,1
  sbb	dx,0
  cmp	di,dx
  jne	@@BankChange
  mov	[word ptr cs:si],0
  jmp	short	@@NextIteration
  	@@BankChange:
  mov	[word ptr cs:si],1
  	@@NextIteration:
  add	si,2
  loop	@@Loop2

  pop	di si
  mov	ax,1
  mov	[inited],al
  retf

	@@NoDetect:
  xor	ax,ax
  retf
ENDP

	PUBLIC	C	deInitGraphics
PROC	C	deInitGraphics
  GETPALETTE
  mov	ax,0003h
  int	10h
  retf
ENDP

	PUBLIC	C	putLine
PROC	C	putLine
	ARG	lineNum:WORD, xOff:WORD, lineLen:WORD, buf:DATAPTR
  push	ds si di

  cld
  mov	bx,[lineNum]			; Decide if bank changes mid-line
  shl	bx,1
  cmp	[cs:bankChanges+bx],0
  jne	@@BankChanged

  mov	ax,[cs:bankNum+bx]
  cmp	ax,[curBank]			; set bank only if necessary
  je	@@NoNewBank
  NEWBANK

  	@@NoNewBank:
  mov	cx,[lineLen]			; blast the line into video memory
  mov	ax,SCREEN_SEG
  mov	es,ax
  mov	di,[cs:lineOffs+bx]
  add	di,[xOff]
  lds	si,[buf]
  shr	cx,1
  rep	movsw
  jnc	@@Exit
  movsb
  	@@Exit:
  pop	di si ds
  leave
  retf

  	@@BankChanged:		      	; slow pixel-by-pixel
  mov	cx,[lineLen]
  mov	dx,[lineNum]
  mov	bx,[xOff]
  lds	si,[buf]
  	@@Loop:
  lodsb
  push	bx cx dx si
  call	far putPixel C,bx,dx,ax
  pop	si dx cx bx
  inc	bx
  loop	@@Loop

  pop	di si ds
  leave
  retf
ENDP

	PUBLIC	C	getLine
PROC	C	getLine
	ARG	lineNum:WORD, xOff:WORD, lineLen:WORD, buf:DATAPTR
  push	ds si di

  cld
  mov	bx,[lineNum]			; Decide if bank changes mid-line
  shl	bx,1
  cmp	[cs:bankChanges+bx],0
  jne	@@BankChanged

  mov	ax,[cs:bankNum+bx]
  cmp	ax,[curBank]			; set bank only if necessary
  je	@@NoNewBank
  NEWBANK

  	@@NoNewBank:
  mov	cx,[lineLen]			; blast the line into video memory
  mov	ax,SCREEN_SEG
  mov	ds,ax
  mov	si,[cs:lineOffs+bx]
  add	si,[xOff]
  les	di,[buf]
  shr	cx,1
  rep	movsw
  jnc	@@Exit
  movsb
  	@@Exit:
  pop	di si ds
  leave
  retf

  	@@BankChanged:		      	; slow pixel-by-pixel
  mov	cx,[lineLen]
  mov	dx,[lineNum]
  mov	bx,[xOff]
  les	di,[buf]
  	@@Loop:
  push	bx cx dx di es
  call	far getPixel C,bx,dx
  pop	es di dx cx bx
  stosb
  inc	bx
  loop	@@Loop

  pop	di si ds
  leave
  retf
ENDP

	PUBLIC	C	putPixel
PROC	C	putPixel
	ARG	x:WORD, y:WORD, colour:BYTE
  mov	bx,[x]
  mov	ax,[y]
  mov	dx,[screenWide]
  mul  	dx
  add	bx,ax
  adc	dx,0
  cmp	dx,[curBank]
  je	@@NoNew
  mov	ax,dx
  NEWBANK			; switch banks if a new bank entered
	@@NoNew:
  mov	ax,SCREEN_SEG		; setup screen segment A000
  mov	es,ax
  mov	al,[colour]		; get color of pixel to plot
  mov	[es:bx],al
  leave
  retf
ENDP

	PUBLIC	C	getPixel
PROC	C	getPixel
	ARG	x:WORD, y:WORD
  mov	ax,[screenWide]
  mul	[y]
  add	ax,[x]
  adc	dx,0
  mov	bx,ax
  cmp	dx,[curBank]
  je	@@noNewBank
  mov	ax,dx
  NEWBANK			; switch banks if a new bank entered
	@@noNewBank:
  mov	ax,SCREEN_SEG		; setup screen segment
  mov	es,ax
  mov	al,[es:bx]
  xor	ah,ah
  leave
  retf
ENDP

	PUBLIC	C	horizLine
PROC	C	horizLine
	ARG	y:WORD, x1:WORD, x2:WORD, colour:BYTE
  push	di

  cld
  mov	bx,[y]				; Decide if bank changes mid-line
  shl	bx,1
  cmp	[cs:bankChanges+bx],0
  jne	@@BankChanged

  mov	ax,[cs:bankNum+bx]
  cmp	ax,[curBank]			; set bank only if necessary
  je	@@NoNewBank
  NEWBANK

  	@@NoNewBank:
  mov	ax,SCREEN_SEG
  mov	es,ax
  mov	ax,[x1]
  mov	di,[cs:lineOffs+bx]
  add	di,ax
  mov	cx,[x2]				; blast the line into video memory
  inc	cx
  sub	cx,ax
  mov	al,[colour]
  mov	ah,al
  shr	cx,1
  rep	stosw
  jnc	@@Exit
  stosb

  	@@Exit:
  pop	di
  leave
  retf

  	@@BankChanged:		      	; slow pixel-by-pixel
  mov	bx,[x1]
  mov	cx,[x2]
  inc	cx
  sub	cx,bx
  mov	dx,[y]
  	@@Loop:
  push	bx cx dx
  mov	al,[colour]
  call	far putPixel C,bx,dx,ax
  pop	dx cx bx
  inc	bx
  loop	@@Loop

  pop	di
  leave
  retf
ENDP

	PUBLIC	C	setPaletteReg
PROC	C	setPaletteReg
	ARG	palNum:WORD,red:BYTE,green:BYTE,blue:BYTE
  mov	bx,[palNum]

  mov	dx,3C8h				; set for the right palette register
  mov	ax,[palNum]
  out	dx,al
  inc	dx

  mov	al,[red]			; red
  shr	al,2
  jnc	@@L1
  cmp	al,63
  je	@@L1
  inc	al
	@@L1:
  out	dx,al

  mov	al,[green]			; green
  shr	al,2
  jnc	@@L2
  cmp	al,63
  je	@@L2
  inc	al
	@@L2:
  out	dx,al

  mov	al,[blue]			; blue
  shr	al,2
  jnc	@@L3
  cmp	al,63
  je	@@L3
  inc	al
	@@L3:
  out	dx,al

  leave
  retf
ENDP

	PUBLIC	C	getPaletteReg
PROC	C	getPaletteReg
	ARG	palNum:WORD,red:DATAPTR,green:DATAPTR,blue:DATAPTR
  push	ds si

  mov	dx,3C7h				; set for right palette register
  mov	ax,[palNum]
  out	dx,al
  mov	dx,3C9h

  in	al,dx				; red
  lds	si,[red]
  shl	al,2
  mov	[ds:si],al
  in	al,dx				; green
  lds	si,[green]
  shl	al,2
  mov	[ds:si],al
  in	al,dx				; blue
  lds	si,[blue]
  shl	al,2
  mov	[ds:si],al

  pop	si ds
  leave
  retf
ENDP

	PUBLIC	C	setBlockPalette
PROC	C	setBlockPalette
	ARG	firstReg:WORD,numRegs:WORD,paletteData:DATAPTR
  push	ds si
  lds	si,[paletteData]
  mov	cx,[numRegs]
  jcxz	@@LExit
  cld

  mov	dx,3C8h				; set for right first pal reg
  mov	ax,[firstReg]
  out	dx,al
  inc	dx

	@@LLoop:
  lodsb			; red
  shr	al,2
  jnc	@@L1
  cmp	al,63
  je	@@L1
  inc	al
  	@@L1:
  out	dx,al

  lodsb			; green
  shr	al,2
  jnc	@@L2
  cmp	al,63
  je	@@L2
  inc	al
  	@@L2:
  out	dx,al

  lodsb			; blue
  shr	al,2
  jnc	@@L3
  cmp	al,63
  je	@@L3
  inc	al
  	@@L3:
  out	dx,al

  loop	@@LLoop

	@@LExit:
  pop	si ds
  leave
  retf
ENDP

	PUBLIC	C	getBlockPalette
PROC	C	getBlockPalette
	ARG	firstReg:WORD,numRegs:WORD,paletteData:DATAPTR
  push	di
  mov	cx,[numRegs]
  jcxz	@@LExit
  les	di,[paletteData]
  cld

  mov	dx,3C7h				; set for right first pal reg
  mov	ax,[firstReg]
  out	dx,al
  mov	dx,3C9h

	@@L1:
  in	al,dx
  shl	al,2
  stosb		; red
  in	al,dx
  shl	al,2
  stosb		; green
  in	al,dx
  shl	al,2
  stosb		; blue
  loop	@@L1

	@@LExit:
  pop	di
  leave
  retf
ENDP

	PUBLIC	C	clearGraphics
PROC	C	clearGraphics
	ARG	colour:BYTE
  push	di

  cmp	[curBank],0
  je	@@NoNewBank
  xor	ax,ax
  NEWBANK

  	@@NoNewBank:
  mov	ax,SCREEN_SEG			; clear bank 0
  mov	es,ax
  xor	di,di
  mov	al,[colour]
  mov	ah,al
  mov	dx,ax
  mov	cx,32768
  rep	stosw

  mov	ax,1				; clear bank 1
  NEWBANK
  mov	ax,dx
  mov	cx,32768
  rep	stosw

  mov	ax,2				; clear bank 2
  NEWBANK
  mov	ax,dx
  mov	cx,32768
  rep	stosw

  mov	ax,3				; clear bank 3
  NEWBANK
  mov	ax,dx
  mov	cx,32768
  rep	stosw

  mov	ax,4				; clear bank 4
  NEWBANK
  mov	ax,dx
  mov	cx,32768
  rep	stosw

  mov	ax,5				; clear bank 5
  NEWBANK
  mov	ax,dx
  mov	cx,32768
  rep	stosw

  mov	ax,6				; clear bank 6
  NEWBANK
  mov	ax,dx
  mov	cx,32768
  rep	stosw

  mov	ax,7				; clear bank 7
  NEWBANK
  mov	ax,dx
  mov	cx,10624
  rep	stosw

  pop	di
  leave
  retf
ENDP

;PROC	newBank	NEAR			; bank number is in AX
;  cli
;  mov	[curBank],ax
;  jmp	[word ptr bankadr]


_tseng:					; Tseng
  cli
  mov	[curBank],ax
  push	ax dx
  and	al,7
  mov	ah,al
  shl	al,3
  or	al,ah
  or	al,01000000b
  mov	dx,3CDh
  out	dx,al
  sti
  pop	dx ax
  ret

_tseng4:				; Tseng 4000 series
  cli
  mov	[curBank],ax
  push	ax dx
  mov	ah,al
  mov	dx,3bfh			; Enable access to extended registers
  mov	al,3
  out	dx,al
  mov	dl,0D8h
  mov	al,0A0h
  out	dx,al
  and	ah,15
  mov	al,ah
  shl	al,4
  or	al,ah
  mov	dl,0CDh
  out	dx,al
  sti
  pop	dx ax
  ret

_trident:				; Trident
  cli
  mov	[curBank],ax
  push	ax dx
  mov	dx,3CEh			; set pagesize to 64k
  mov	al,6
  out	dx,al
  inc	dl
  in	al,dx
  dec	dl
  or	al,4
  mov	ah,al
  mov	al,6
  out	dx,ax

  mov	dl,0C4h			; switch to BPS mode
  mov	al,0Bh
  out	dx,al
  inc	dl
  in	al,dx
  dec	dl

  mov	ah,[byte ptr curBank]
  xor	ah,2
  mov	dx,3C4h
  mov	al,0Eh
  out	dx,ax
  sti
  pop	dx ax
  ret

_video7:				; Video 7
  cli
  mov	[curBank],ax
  push	ax dx cx
  and	ax,15
  mov	ch,al
  mov	dx,3C4h
  mov	ax,0EA06h
  out	dx,ax
  mov	ah,ch
  and	ah,1
  mov	al,0F9h
  out	dx,ax
  mov	al,ch
  and	al,1100b
  mov	ah,al
  shr	ah,2
  or	ah,al
  mov	al,0F6h
  out	dx,al
  inc	dx
  in	al,dx
  dec	dx
  and	al,NOT 1111b
  or	ah,al
  mov	al,0F6h
  out	dx,ax
  mov	ah,ch
  mov	cl,4
  shl	ah,cl
  and	ah,100000b
  mov	dl,0CCh
  in	al,dx
  mov	dl,0C2h
  and	al,NOT 100000b
  or	al,ah
  out	dx,al
  sti
  pop	cx dx ax
  ret

_paradise:				; Paradise
  cli
  mov	[curBank],ax
  push	ax dx
  mov	dx,3CEh
  mov	ax,50Fh			; turn off write protect on VGA registers
  out	dx,ax
  mov	ah,[byte ptr curBank]
  shl	ah,4			; change 64k bank number into 4k bank number
  mov	al,9
  out	dx,ax
  sti
  pop	dx ax
  ret

_chipstech:				; Chips & Tech
  cli
  mov	[curBank],ax
  push	ax dx
  mov	dx,46E8h		; place chip in setup mode
  mov	ax,1Eh
  out	dx,ax
  mov	dx,103h			; enable extended registers
  mov	ax,0080h
  out	dx,ax
  mov	dx,46E8h		; bring chip out of setup mode
  mov	ax,0Eh
  out	dx,ax
  mov	ah,[byte ptr curBank]
  shl	ah,2			; change 64k bank number into 16k bank number
  mov	al,10h
  mov	dx,3D6h
  out	dx,ax
  sti
  pop	dx ax
  ret

_ativga:				; ATI VGA Wonder
  cli
  mov	[curBank],ax
  push	ax dx
  mov	ah,al
  mov	dx,1CEh
  mov	al,0B2h
  out	dx,al
  inc	dl
  in	al,dx
  shl	ah,1
  and	al,0E1h
  or	ah,al
  mov	al,0B2h
  dec	dl
  out	dx,ax
  sti
  pop	dx ax
  ret

_everex:				; Everex
  cli
  mov	[curBank],ax
  push	ax dx cx
  mov	cl,al
  mov	dx,3C4h
  mov	al,8
  out	dx,al
  inc	dl
  in	al,dx
  dec	dl
  shl	al,1
  shr	cl,1
  rcr	al,1
  mov	ah,al
  mov	al,8
  out	dx,ax
  mov	dl,0CCh
  in	al,dx
  mov	dl,0C2h
  and	al,0DFh
  shr	cl,1
  jc	@@nob2
  or	al,20h
  	@@nob2:
  out	dx,al
  sti
  pop	cx dx ax
  ret

_aheada:				; Ahead Systems Ver A
  cli
  mov	[curBank],ax
  push	ax dx cx
  mov	ch,al
  mov	dx,3CEh			; Enable extended registers
  mov	ax,200Fh
  out	dx,ax
  mov	dl,0CCh			; bit 0
  in	al,dx
  mov	dl,0C2h
  and	al,11011111b
  shr	ch,1
  jnc	@@skpa
  or	al,00100000b
  	@@skpa:
  out	dx,al
  mov	dl,0CFh			; bits 1,2,3
  xor	al,al
  out	dx,al
  inc	dx
  in	al,dx
  dec	dx
  and	al,11111000b
  or	al,ch
  mov	ah,al
  xor	al,al
  out	dx,ax
  sti
  pop	cx dx ax
  ret

_aheadb:				; Ahead Systems Ver B
  cli
  mov	[curBank],ax
  push	ax dx cx
  mov	ch,al
  mov	dx,3CEh			; Enable extended registers
  mov	ax,200Fh
  out	dx,ax
  mov	ah,ch
  mov	cl,4
  shl	ah,cl
  or	ah,ch
  mov	al,0Dh
  out	dx,ax
  sti
  pop	cx dx ax
  ret

_oaktech:				; Oak Technology Inc OTI-067
  cli
  mov	[curBank],ax
  push	ax dx
  and	al,15
  mov	ah,al
  shl	al,4
  or	ah,al
  mov	al,11h
  mov	dx,3DEh
  out	dx,ax
  sti
  pop	dx ax
  ret

_genoa:					; GENOA GVGA
  cli
  mov	[curBank],ax
  push	ax dx
  mov	ah,al
  shl	al,3
  or	ah,al
  mov	al,6
  or	ah,40h
  mov	dx,3C4h
  out	dx,ax
  sti
  pop	dx ax
  ret

_ncr:					; NCR 77C22E
  cli
  mov	[curBank],ax
  push	ax ax
  push	dx
  shl	al,2			; change 64k bank number into 16k bank number
  mov	ah,al
  mov	al,18h
  mov	dx,3C4h
  out	dx,ax
  mov	ax,19h
  out	dx,ax
  sti
  pop	dx ax
  ret

_compaq:				; Compaq
  cli
  mov	[curBank],ax
  push	ax dx
  mov	dx,3CEh
  mov	ax,50Fh			; unlock extended registers
  out	dx,ax
  mov	ah,[byte ptr curBank]
  shl	ah,4			; change 64k bank number into 4k bank number
  mov	al,45h
  out	dx,ax
  sti
  pop	dx ax
  ret

_vesa:				; Vesa SVGA interface
  cli
  mov	[curBank],ax
  push	ax bx cx dx
  mov	cl,[vesashift]
  shl	ax,cl
  mov	dx,ax
  xor	bx,bx
  mov	ax,4F05h
  int	10h
  sti
  pop	dx cx bx ax
  ret

_nobank:
  cli
  mov	[curBank],ax
  sti
  ret
;ENDP


MACRO	BKADR	func
  mov	[func],1
  mov	[bankadr],OFFSET _&func
ENDM

MACRO	NOJMP
  local	lbl
  jmp	short	lbl
	lbl:
ENDM


PROC	whichVGA	NEAR
  push	si di

  cmp	[inited],1
  jne	@@goTest
  mov	ax,[retval]
  pop	di si
  ret
	@@goTest:
  mov	[bankadr],OFFSET _nobank
  xor	ax,ax
  mov	[curBank],ax
  mov	[vga512],ax
  mov	[vga1024],ax
  mov	[cirrus],ax
  mov	[everex],ax
  mov	[paradise],ax
  mov	[tseng],ax
  mov	[trident],ax
  mov	[t8900],ax
  mov	[ativga],ax
  mov	[aheada],ax
  mov	[aheadb],ax
  mov	[oaktech],ax
  mov	[video7],ax
  mov	[chipstech],ax
  mov	[tseng4],ax
  mov	[genoa],ax
  mov	[ncr],ax
  mov	[compaq],ax
  mov	[vesa],ax

  mov	ax,cs
  mov	es,ax
  lea	di,[vesaBuf]
  mov	ax,4F00h
  int	10h
  cmp	ax,4Fh
  jnz	@@noVESA
  BKADR	vesa
  mov	[vga512],1
  mov	[vga1024],1
; jmp	@@fini     			;*** uncomment to use VESA only

	@@noVESA:
  mov	si,1
  mov	ax,0C000h
  mov	es,ax
  cmp	[word ptr es:40h],'13'		; ATI Signiture on the Video BIOS
  jnz	@@noATI
  BKADR	ativga
  cli
  mov	dx,1CEh
  mov	al,0BBh
  out	dx,al
  inc	dl
  in	al,dx
  sti
  and	al,20h
  jz	@@no512
  mov	[vga512],1
	@@no512:
  jmp	@@fini

	@@noATI:
  mov	ax,7000h			; Test for Everex
  xor	bx,bx
  cld
  int	10h
  cmp	al,70h
  jnz	@@noEverex
  BKADR	everex
  and	ch,11000000b		; how much memory on board?
  jz	@@skp
  mov	[vga512],1
 	@@skp:			; fall through for Everex boards using Trident or Tseng4000

	@@noEverex:
  mov	ax,0BF03h			; Test for Compaq
  xor	bx,bx
  mov	cx,bx
  int	10h
  cmp	ax,0BF03h
  jnz	@@noCompaq
  test	cl,40h				; is 640x480x256 available?
  jz	@@noCompaq
  BKADR	compaq
  mov	[vga512],1
  jmp	@@fini

	@@noCompaq:
  mov	dx,3C4h				; Test for NCR 77C22E
  mov	ax,0FF05h
  call	_isport2
  jnz	@@noNCR
  mov	ax,5		       	; Disable extended registers
  out	dx,ax
  mov	ax,0FF10h		; Try to write to extended register 10
  call	_isport2		; If it writes then not NCR
  jz	@@noNCR
  mov	ax,105h			; Enable extended registers
  out	dx,ax
  mov	ax,0FF10h
  call	_isport2
  jnz	@@noNCR			; If it does NOT write then not NCR
  BKADR	ncr
  mov	[vga512],1
  jmp	@@fini

	@@noNCR:
  mov	dx,3C4h				;Test for Trident
  mov	al,0Bh
  out	dx,al
  inc	dl
  in	al,dx
  cmp	al,06h
  ja	@@noTrident
  cmp	al,2
  jb	@@noTrident
  BKADR	trident
  cmp	al,3
  jb	@@no89
  mov	[t8900],1
  mov	dx,3D5h
  mov	al,1Fh
  out	dx,al
  inc	dx
  in	al,dx
  and	al,3
  cmp	al,1
  jb	@@notmem
  mov	[vga512],1
  je	@@notmem
  mov	[vga1024],1
	@@notmem:
  jmp	@@fini

	@@no89:
  mov	[vga512],1
  jmp	@@fini

	@@noTrident:
  mov	ax,6F00h			; Test for Video 7
  xor	bx,bx
  cld
  int	10h
  cmp	bx,'V7'
  jnz	@@noVideo7
  BKADR	video7
  mov	ax,6F07h
  cld
  int	10h
  and	ah,7Fh
  cmp	ah,1
  jbe	@@skp2
  mov	[vga512],1
	@@skp2:
  cmp	ah,3
  jbe	@@skp3
  mov	[vga1024],1
	@@skp3:
  jmp	@@fini

	@@noVideo7:
  mov	dx,3D4h				; Test for GENOA GVGA
  mov	ax,032Eh		; check for Herchi Register
  call	_isport2
  jnz	@@noGenoa
  mov	dx,3C4h			; check for memory segment register
  mov	ax,3F06h
  call	_isport2
  jnz	@@noGenoa
  BKADR	genoa
  mov	[vga512],1
  jmp	@@fini

	@@noGenoa:
  call	_cirrus				; Test for Cirrus
  cmp	[cirrus],0
  je	@@noCirrus
  jmp	@@fini

	@@noCirrus:
  mov	dx,3CEh				; Test for Paradise
  mov	al,9			; check Bank switch register
  out	dx,al
  inc	dx
  in	al,dx
  dec	dx
  or	al,al
  jnz	@@noParadise

  mov	ax,50Fh			; turn off write protect on VGA registers
  out	dx,ax
  mov	dx,OFFSET _pdrsub
  mov	cx,1
  call	_chkbk
  jc	@@noParadise		; if bank 0 and 1 same not paradise
  BKADR	paradise
  mov	dx,3CEh
  mov	al,0Bh			; 512k detect from Bob Berry
  out	dx,al
  inc	dx
  in	al,dx
  test	al,80h			; if top bit set then 512k
  jz	@@nop512
  mov	[vga512],1
	@@nop512:
  jmp	@@fini

	@@noParadise:
  mov	ax,5F00h			; Test for Chips & Tech
  xor	bx,bx
  cld
  int	10h
  cmp	al,5Fh
  jnz	@@noChipsTech
  BKADR	chipstech
  cmp	bh,1
  jb	@@skp4
  mov	[vga512],1
	@@skp4:
  jmp	@@fini

	@@noChipsTech:
  xor	ch,ch				; check for Tseng 4000 series
  mov	dx,3D4h
  mov	ax,0F33h
  call	_isport2
  jnz	@@noTseng4
  mov	ch,1

  mov	dx,3BFh			; Enable access to extended registers
  mov	al,3
  out	dx,al
  mov	dx,3D8h
  mov	al,0A0h
  out	dx,al
  jmp	short @@yes4

	@@noTseng4:
  mov	dx,3D4h			; Test for Tseng 3000 or 4000
  mov	ax,1F25h		; is the Overflow High register there?
  call	_isport2
  jnz	@@noTseng
  mov	al,03Fh			; bottom six bits only
  jmp	short @@yes3
	@@yes4:
  mov	al,0FFh
	@@yes3:
  mov	dx,3CDh			; test bank switch register
  call	_isport1
  jnz	@@noTseng
  BKADR	tseng
  cmp	ch,0
  jnz	@@t4mem
  mov	[vga512],1
  jmp	@@fini

	@@t4mem:
  mov	dx,3D4h			; Tseng 4000 memory detect 1meg
  mov	al,37h
  out	dx,al
  inc	dx
  in	al,dx
  test	al,1000b		; if using 64kx4 RAMs then no more than 256k
  jz	@@nomem
  and	al,3
  cmp	al,1			; if 8 bit wide bus then only two 256kx4 RAMs
  jbe	@@nomem
  mov	[vga512],1
  cmp	al,2			; if 16 bit wide bus then four 256kx4 RAMs
  je	@@nomem
  mov	[vga1024],1		; full meg with eight 256kx4 RAMs
	@@nomem:
  BKADR	tseng4
  jmp	@@fini

	@@noTseng:
  mov	dx,3CEh				;Test for Above A or B chipsets
  mov	ax,200Fh
  out	dx,ax
  inc	dx
  NOJMP
  in	al,dx
  cmp	al,21h
  jz	@@verb
  cmp	al,20h
  jnz	@@noAbove
  BKADR	aheada
  mov	[vga512],1
  jmp	short @@fini

	@@verb:
  BKADR	aheadb
  mov	[vga512],1
  jmp	short @@fini

	@@noAbove:
  mov	dx,3DEh				; Test for Oak Technology
  mov	ax,0FF11h		; look for bank switch register
  call	_isport2
  jnz	@@noOak
  BKADR	oaktech
  mov	al,0Dh
  out	dx,al
  inc	dx
  NOJMP
  in	al,dx
  test	al,80h
  jz	@@noOak
  mov	[vga512],1
  jmp	short @@fini

	@@noOak:
  xor	si,si

	@@fini:
  mov	ax,si
  mov	[retval],ax
  pop	di si
  ret
ENDP

PROC	_cirrus	NEAR
  mov	dx,3d4h		; assume 3dx addressing
  mov	al,0ch		; screen a start address hi
  out	dx,al		; select index
  inc	dx		; point to data
  mov	ah,al		; save index in ah
  in	al,dx		; get screen a start address hi
  xchg	ah,al		; swap index and data
  push	ax		; save old value
  push	dx		; save crtc address
  xor	al,al		; clear crc
  out	dx,al		; and out to the crtc

  mov	al,1fh		; Eagle ID register
  dec	dx		; back	to index
  out	dx,al		; select index
  inc	dx		; point to data
  in	al,dx		; read the id register
  mov	bh,al		; and save it in bh

  mov	cl,4		; nibble swap rotate count
  mov	dx,3c4h		; sequencer/extensions
  mov	bl,6		; extensions enable register

  ror	bh,cl		; compute extensions disable value
  mov	ax,bx		; extensions disable
  out	dx,ax		; disable extensions
  inc	dx		; point to data
  in	al,dx		; read enable flag
  or	al,al		; disabled ?
  jnz   @@Exit		; nope, not an cirrus

  ror	bh,cl		; compute extensions enable value
  dec	dx		; point to index
  mov	ax,bx		; extensions enable
  out	dx,ax		; enable extensions
  inc	dx		; point to data
  in	al,dx		; read enable flag
  cmp	al,1		; enabled ?
  jne	@@Exit		; nope, not an cirrus
  mov	[cirrus],1
  mov	[bankadr],OFFSET _nobank

	@@Exit:
  pop	dx		; restore crtc address
  dec	dx		; point to index
  pop	ax		; recover crc index and data
  out	dx,ax		; restore crc value
  ret
ENDP

PROC	_chkbk	NEAR			; bank switch check routine
  mov	di,0B800h
  mov	es,di
  xor	di,di
  mov	bx,1234h
  call	_gochk
  jnz	@@badchk
  mov	bx,4321h
  call	_gochk
  jnz	@@badchk
  clc
  ret
	@@badchk:
  stc
  ret
ENDP

PROC	_gochk	NEAR
  push	si
  mov	si,bx

  mov	al,cl
  call	dx
  xchg	bl,[es:di]
  mov	al,ch
  call	dx
  xchg	bh,[es:di]

  xchg	si,bx

  mov	al,cl
  call	dx
  xor	bl,[es:di]
  mov	al,ch
  call	dx
  xor	bh,[es:di]

  xchg	si,bx

  mov	al,ch
  call	dx
  mov	[es:di],bh
  mov	al,cl
  call	dx
  mov	[es:di],bl

  xor	al,al
  call	dx
  or	si,si
  pop	si
  ret
ENDP

PROC	_pdrsub	NEAR			; Paradise
  push	dx
  mov	ah,al
  mov	dx,3CEh
  mov	al,9
  out	dx,ax
  pop	dx
  ret
ENDP

PROC	_isport2	NEAR
  push	bx
  mov	bx,ax
  out	dx,al
  mov	ah,al
  inc	dx
  in	al,dx
  dec	dx
  xchg	al,ah
  push	ax
  mov	ax,bx
  out	dx,ax
  out	dx,al
  mov	ah,al
  inc	dx
  in	al,dx
  dec	dx
  and	al,bh
  cmp	al,bh
  jnz	@@noport
  mov	al,ah
  mov	ah,0
  out	dx,ax
  out	dx,al
  mov	ah,al
  inc	dx
  in	al,dx
  dec	dx
  and	al,bh
  cmp	al,0
	@@noport:
  pop	ax
  out	dx,ax
  pop	bx
  ret
ENDP

PROC	_isport1	NEAR
  mov	ah,al
  in	al,dx
  push	ax
  mov	al,ah
  out	dx,al
  in	al,dx
  and	al,ah
  cmp	al,ah
  jnz	@@noport
  mov	al,0
  out	dx,al
  in	al,dx
  and	al,ah
  cmp	al,0
	@@noport:
  pop	ax
  out	dx,al
  ret
ENDP

PROC	setMode	NEAR		; Set 800x600x256
  cmp	[compaq],0
  jz	@@noCompaq
  mov	ax,2Eh
  jmp	@@godo
	@@noCompaq:
  cmp	[genoa],0
  jz	@@noGenoa
  mov	ax,5Eh
  jmp	@@godo
	@@noGenoa:
  cmp	[ncr],0
  jz	@@noNCR
  mov	ax,5Ch
  jmp	@@godo
	@@noNCR:
  cmp	[oaktech],0
  jz	@@noOak
  mov	ax,56h
  jmp	@@godo
	@@noOak:
  cmp	[aheada],0
  jnz	@@
  cmp	[aheadb],0
  jz	@@noAbove
	@@:
  mov	ax,62h
  jmp	short @@godo
	@@noAbove:
  cmp	[everex],0
  jz	@@noEverex
  mov	ax,70h
  mov	bl,31h
  jmp	short @@godo
	@@noEverex:
  cmp	[ativga],0
  jz	@@noATI
  mov	ax,63h
  jmp	short @@godo
	@@noATI:
  cmp	[trident],0
  jz	@@noTrident
  mov	ax,5Eh
  jmp	short @@godo
	@@noTrident:
  cmp	[video7],0
  jz	@@noVideo7
  mov	ax,6F05h
  mov	bl,69h
  jmp	short @@godo
	@@noVideo7:
  cmp	[chipstech],0
  jz	@@noChipsTech
  mov	ax,7Bh
  jmp	short @@godo
	@@noChipsTech:
  cmp	[paradise],0
  jz	@@noParadise
  mov	ax,5Fh
  jmp	short @@godo
	@@noParadise:
  cmp	[tseng],0
  jz	@@noTseng
  mov	ax,30h
  jmp	short	@@godo
  	@@noTseng:
  cmp	[vesa],0
  jz	@@noVESA
  mov	ax,4F02h
  mov	bx,103h
	@@godo:
  int	10h

  mov	[curBank],-1
  mov	ax,SCREEN_WIDE
  cmp	[compaq],0
  jz	@@noKludge
  mov	ax,1024
	@@noKludge:
  mov	[screenWide],ax
  mov	ax,1
  ret

	@@noVESA:
  xor	ax,ax
  ret
ENDP

	ENDS

END