	name	tseng

	.286

_text	segment	byte public 'CODE'

	ASSUME	cs:_text,ds:nothing,es:nothing

setpage	MACRO	read, write
	mov	al,read
	shl	al,3
	or	al,write	; port = (src << 3) | dest
	or	al,40h
	mov	dx,03cdh
	out	dx,al		; set the page
ENDM

	org	0

MaxCmd	equ	14

Header:
	dd	-1		; link to next device driver
	dw	0c000h		; device attribute word
	dw	Strat		; strategy entry point
	dw	Intr		; interrupt entry point
	db	'XWVGA   '	; name

RHPtr	dd	?		; pointer to request header

Dispatch:
	dw	Init		;  0 = initialize driver
	dw	Error		;  1 = media check (block device)
	dw	Error		;  2 = build BIOS parameter block
	dw	IRead		;  3 = IOCTL read
	dw	Read		;  4 = read
	dw	Error		;  5 = nondestructive read
	dw	Error		;  6 = input status
	dw	Error		;  7 = flush input buffers
	dw	Error		;  8 = write
	dw	Error		;  9 = write with verify
	dw	Error		; 10 = output status
	dw	Error		; 11 = flush output buffers
	dw	IWrite		; 12 = IOCTL write
	dw	Dummy		; 13 = device open
	dw	Dummy		; 14 = device close

vga_conf	STRUC
version		db	?
spare		db	?
close_off	dw	?
close_seg	dw	?
page_off	dw	?	; change page
page_seg	dw	?
copy_off	dw	?
copy_seg	dw	?
move_off	dw	?
move_seg	dw	?
vga_conf	ENDS

ret_data:
	db	1		; version
	db	0		; spare
	dw	offset VGAClose
	dw	0
	dw	offset VGASetPage
	dw	0
	dw	0
	dw	0
	dw	0
	dw	0
end_data:

Strat	PROC FAR
	mov	word ptr cs:[RHPtr],bx
	mov	word ptr cs:[RHPtr+2],es
	ret
Strat	ENDP

Intr	PROC FAR
	push	ax
	push	bx
	push	cx
	push	di
	push	es
	push	ds
	mov	ax,cs
	mov	ds,ax
	ASSUME	ds:_text
	les	di,[RHPtr]
	mov	bl,es:[di+2]		; command cod3
	xor	bh,bh
	cmp	bx,MaxCmd
	jle	Intr1			; command is within range
	call	Error
	jmp	short $L2
Intr1:
	shl	bx,1			; turn into a pointer
	call	word ptr [bx+Dispatch]
$L2:
	or	ax,0100h		; done bit
	mov	es:[di+3],ax		; return code
	pop	ds
	pop	es
	pop	di
	pop	cx
	pop	bx
	pop	ax
	ret
Intr	ENDP

Error	PROC NEAR
	mov	ax,08003h		; non-existant command
	ret
Error	ENDP

Dummy	PROC NEAR
	xor	ax,ax
	ret
Dummy	ENDP

Read	PROC NEAR
	mov	word ptr es:[di+12h],0		; return EOF
	ret
Read	ENDP

IRead	PROC NEAR
	push	es
	push	di
	push	si
	mov	cx,es:[di+12h]		; bytes requested
	cmp	cx,size vga_conf
	jle	$L1
	mov	cx,size vga_conf
	mov	es:[di+12h],cx
$L1:
	jcxz	$L3
	les	di,es:[di+0eh]		; pointer to user's buffer
	mov	si,offset ret_data
	cld
	rep	movsb
$L3:
	pop	si
	pop	di
	pop	es
	xor	ax,ax			; success
	ret
IRead	ENDP

old_mode	db	?
mono_modes:
	db	11h		; 640x480
	db	29h		; 800x600
	db	37h		; 1024x768 not supported
color_modes:
	db	2eh		; 640x480
	db	30h		; 800x600
	db	0		; 1024x768 not supported
color_copy:
	dw	offset copy640
	dw	offset copy800
	dw	offset copy1024

IWrite	PROC NEAR
	push	es
	push	di
	les	di,es:[di+0eh]		; pointer to user's buffer
	mov	bx,es:[di]
	; sanity check
	dec	bl
	cmp	bl,2
	jbe	$L4
	; arg error
	mov	ax,08001h
	jmp	short $L9
$L4:
	or	bh,bh		; non-zero for color
	mov	bh,0
	jne	color
	mov	al,byte ptr mono_modes[bx]
	jmp	short $L5
color:
	shl	bx,1
	mov	ax,word ptr color_copy[bx]
	mov	ret_data.copy_off,ax
	mov	ret_data.move_off,ax
	shr	bx,1
	mov	al,byte ptr color_modes[bx]
$L5:
	or	al,al
	jnz	$L6
	; non supported mode
	mov	ax,08002
	jmp	short $L9
$L6:
	mov	dl,al		; save mode
	mov	ah,0fh
	int	10h
	mov	old_mode,al
	mov	al,dl
	xor	ah,ah		; function 0 = set mode
	int	10h
	xor	ax,ax		; success
$L9:
	pop	di
	pop	es
	ret
IWrite	ENDP

VGAClose	PROC FAR
	push	ds
	mov	ax,cs
	mov	ds,ax
	mov	al,old_mode
	xor	ah,ah
	int	10h
	pop	ds
	ret
VGAClose	ENDP

VGASetPage	PROC FAR
	push	bp
	mov	bp,sp
	mov	al,6[bp]	; get page number
	mov	ah,al
	shl	al,3
	or	al,ah
	or	al,40h
	mov	dx,03cdh
	out	dx,al
	pop	bp
	ret
VGASetPage	ENDP

include	acopy.asm

Init	PROC NEAR
	mov	word ptr es:[di+14],offset Init	; free memory
	mov	word ptr es:[di+16],cs		; segment of free memory
	mov	ret_data.close_seg,cs
	mov	ret_data.page_seg,cs
	mov	ret_data.copy_seg,cs
	mov	ret_data.move_seg,cs
	mov	cx,dx
	mov	dx,offset copyright
	mov	ah,9
	int	21h
	mov	dx,cx
	xor	ax,ax			; success
	ret
Init	ENDP

copyright db	10, 13, 'Tseng VGA driver version 1.0 installed.', 10, 13
	db	'Copyright (c) 1991 Starnet Communications '
	db	'Corporation, Inc. All rights reserved.',10,13,'$'

_text	ENDS
	END
