;----------------------------------------------------------------------------
;GuruMode	-	12 new 256 color modes for the IBM VGA and
;			compatibles.  (all modes are "tweaked" modes, e.g.
;			four bitplanes are used, with a complete pixel in
;			each plane.)
;Calling protocol	int gurumode(unsigned int mode);
;Valid values mode for are:
;		0	320x175			6	360x175
;		1	320x200			7	360x200
;		2	320x240			8	360x240
;		3	320x350			9	360x350
;		4	320x400			a	360x400
;		5	320x480			b	360x480
;
;Returns	0	if call was successful
;		-1	if VGA wasn't detected
;		-2	if selected mode was out of range
;
;Terms of use	-	Use and distribute freely as long as source remains
;			100% unchanged.  Donations of 10$, or any amount
;			are received with gratitude (I'm a student with
;			a rather tigth budget).
;					(C) 8-02-1992 Per Ole Klemetsrud
;					Hertug Skulesgt. 15c
;					0652 Oslo, Norway
;
;Clarke's Third Law:	"Any sufficiently advanced technology is
; 			indistinguishable from magic."
;----------------------------------------------------------------------------
        .model  small
        .code
        public  _gurumode
_gurumode proc  NEAR mode:WORD
        push    bp              ;Save stack pointer
        mov     bp,sp           ;Get new stack pointer
        push    si
        push    di

	mov	ax,01a00h	;VGA BIOS returns 01Ah in AL if call was valid
	int	10h
	cmp	al,01ah
	je	VGApresent
	mov	ax,-1
	jmp	exit
VGApresent:
	mov	ax,-2		;Error code
	mov	bx,[mode]	;Get selected mode
	cmp	bx,0bh		;Check if mode is valid
	jg	exit

	mov	ax,0013h
	int	10h		;Start with BIOS mode 13h

	mov	dx,03c4h	;Sequencer Register
	mov	cl,[clocktab+bx]
	cmp	cl,00h		;Check if reset is necessary
	je	Skip_Reset

        mov	ax,0100h	;Index 0, (Reset Register)
        out	dx,ax		;Set the system in reset conditon

        mov	dx,3c2h		;Miscellaneous output register
        mov	al,cl		;Set new sync polarity and clock frequency
        out	dx,al

        mov	dx,3c4h		;Sequencer register
        mov	ax,0300h	;Index 0, (Reset Register)
        out	dx,ax		;Release reset
Skip_Reset:
        mov	ax,0604h	;Index 4, Disable Chain 4 (Set bit 3 to 0)
        out	dx,ax		;Part of the "Tweak Settings"

	mov	ax,0a000h	;This is a good time to clear RAM to
	mov	es,ax		;avoid a flick of trash during mode change
	xor	di,di
	xor	ah,ah		;ES:DI=Video Ram, AX=0000
	mov	cx,(0ffffh/2)	;Entire Video Segment in words
rep	stosw

        mov	dx,03d4h	;Start filling the CRT controller registers
        mov	si,offset [Regtab]
	mov	cx,3		;Start with the "tweak mode" settings
	cmp	bl,5		;and continue with horizontal settings
	jbe	CRT1		;if necessary
	mov	cx,10

CRT1:  	lodsw
	out	dx,ax
	loop	CRT1		;Now thru with "Tweak" settings

	shl	bx,1		;Make BX a word index, instead of a byte index
	mov	si,[vertab+bx]	;Get address of table to use
	cmp	si,0
	je	noerr		;Do more changes necessary.
	cmp	si,1		
	je	Set400

	mov	cx,8		;Fill CRT controller registers with
CRT2:	lodsw			;info about horizontal resolution.
	out	dx,ax
	loop	CRT2

noerr:	xor	ax,ax
exit:	pop     di
	pop     si
	pop     bp		;Restore registers
	ret

Set400:	mov	ax,04009h	;Mode only requiers normal vertical resolution
	out	dx,ax
	jmp	noerr

_gurumode endp

        .data
Regtab	label	word
	dw	00e11h		;Index 11, Turn off write protect
	dw	00014h		;Index 14, Turn off dword mode
	dw	0e317h		;Index 17, Turn on byte mode
;----------------------------------------------------------------------------
;Data to the set the CRT controller to 360 horizontal pixels.
;Horizontal retrace and blanking periods are based on mode 10h and 12h.
;----------------------------------------------------------------------------
	db	00h,06bh	;Horizontal Total		107
	db	01h,059h	;Horizontal Display End		 89
	db	02h,05ah	;Start Horizontal Blanking	 90
	db	03h,08eh	;End Horizontal Blanking	 
	db	04h,05eh	;Start Horizontal Retrace	 94
	db	05h,08ah	;End Horizontal Retrace 	 
	db	13h,02dh	;Offset register		 90

;----------------------------------------------------------------------------
;Data to the set the CRT controller to 480 scanlines, originaly used 
;by BIOS mode 12h.  Refer to Programmers guide to the EGA/VGA, by 
;Richard F. Ferraro for details about display timing.
;----------------------------------------------------------------------------
vert480	label	word
	db	009h,01000000b	;Maximum Scan Line		  0
	db	007h,00111110b	;Overflow register
	db	006h,00bh	;Vertical Total			523
	db	010h,0eah	;Vertical Retrace Start 	490
	db	011h,08ch	;Vertical Retrace End
	db	015h,0e7h	;Start Vertical Blanking	487
	db	016h,004h	;End Vertical Blanking
	db	012h,0dfh	;Vertical Display End		479
	db	012h,0dfh	;Safe dummy for neat program flow
;----------------------------------------------------------------------------
;Data to the CRT controller to set the display to 350 scanlines,
;originaly used by BIOS mode 10h.  Refer to Programmers guide to the EGA/VGA,
;by Richard F. Ferraro for details about display timing.
;----------------------------------------------------------------------------
vert350	label	word
	db	009h,01000000b	;Maximum Scan Line		  0
	db	007h,00011111b	;Overflow register
	db	006h,0bfh	;Vertical Total    		447
	db	010h,083h	;Vertical Retrace Start 	387
	db	011h,085h	;Vertical Retrace End
	db	015h,063h	;Start Vertical Blanking	355
	db	016h,0bah	;End Vertical Blanking
	db	012h,05dh	;Vertical Display End		349
	db	012h,05dh	;Safe dummy for neat program flow
;----------------------------------------------------------------------------
;Sync polarities and horizontal clock frequencies for the different modes
;----------------------------------------------------------------------------
clocktab	label	byte
	db	0a3h, 000h, 0e3h, 0a3h, 000h, 0e3h
	db	0a7h, 067h, 0e7h, 0a7h, 067h, 0e7h

vertab	dw	vert350+2,0000h, vert480+2, vert350, 0001h, vert480
	dw	vert350+2,0000h, vert480+2, vert350, 0001h, vert480
        end