;--------------------------------------------------------------------------
; This is file CIRRUS.ASM
;
; Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
; Copyright (C) 1992 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
; Copyright (C) 1993 Hartmut Schirmer, Feldstr. 118, 2300 Kiel 1, Germany
; Copyright (C) 1993 Ben Jos Walbeehm, Lijsterbeslaan 20, 5248 BB Rosmalen,
;                                                                 Netherlands
;
; This file is distributed under the terms listed in the document
; "copying.dj", available from DJ Delorie at the address above.
; A copy of "copying.dj" should accompany this file; if not, a copy
; should be available from where this file was obtained.  This file
; may not be distributed without a verbatim copy of "copying.dj".
;
; This file is distributed WITHOUT ANY WARRANTY; without even the implied
; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
;--------------------------------------------------------------------------
; 64K mode added by J.Dittrich dittrich@ifk20.mach.uni-karlsruhe.de
; 16M mode doesn't work!     ***!!!***  But it does!  See below (BJW).
;--------------------------------------------------------------------------
; A number of modes (the 2Mb-video-RAM modes amongst others) added by 
; B.J. Walbeehm (Walbeehm@fsw.ruu.nl).
;
; NOTE:  The 16M mode can be made to work properly when using DISP V1.57
; =====  or better! To accomplish this, put the following two lines in the
;        "Bytes per line scan table for TrueColour Mode" (see CONFIG.DIS):
;            bytes_per_line_true=0,2048
;            bytes_per_line_true=3,2048
;--------------------------------------------------------------------------
;
; This driver supports Cirrus CL-GD542X Chipsets
; Check your BIOS documentation if all of below modes are supported !
;
include grdriver.inc
cseg    segment byte public 'code'
	assume  cs:cseg, ds:cseg, es:cseg, ss:nothing


;--------------------------------------------------------------------------
; DRIVER HEADER
;  The following entries MUST match the structure and constant
;  declarations in the file 'grdriver.h' of the GRX graphics library
;  The mode word should contain the following bitfields:
;     - the GRD_NEW_DRIVER bit set for any new format driver
;     - the adapter type field should be specified
;     - the memory size field should be specified
;     - the paging mode field should be specified
;  The mode set routine will OR in the plane bitfield as it will
;  change when different color number modes are requested.
;--------------------------------------------------------------------------

	dw      offset mode_set_routine
	dw      offset paging_routine
mode_W  dw      GRD_NEW_DRIVER+GRD_VGA+GRD_1024K+GRD_NO_RW
;
; The 'def_xx' fields are filled in by go32 from the corresponding
; fields of the 'GO32' environment variable
;
def_tw  dw      80              ; text width
def_th  dw      25              ; text height
def_gw  dw      640             ; graphics width
def_gh  dw      480             ; graphics height
def_nc  dw      16              ; graphics colors
	dw      offset driver_init_routine
	dw      offset text_mode_table
	dw      offset graphics_mode_table

;
; Biggest text and graphics sizes
;
Max_TW  equ     132
Max_TH  equ     50
Max_GWn equ     800             ; non interlaced!!!
Max_GHn equ     600
Max_GW  equ     1280            ; may be interlaced
Max_GH  equ     1024


;--------------------------------------------------------------------------
; TABLE OF SUPPORTED TEXT MODES
;       - keep sorted by size
;       - end with an all 0 entry
;       - BIOS field = 0xff disables it
;       - fields:
;               width,  height, colors, BIOS#+  setup_procedure_index*256
;--------------------------------------------------------------------------
text_mode_table         label word
	dw      80,     25,      2,     007h +  00000h
	dw      40,     25,     16,     001h +  00000h ; also: mode 000h
	dw      40,     50,     16,     001h +  00100h ; also: mode 000h *
	dw      80,     25,     16,     003h +  00000h ; also: mode 002h
	dw      80,     50,     16,     003h +  00100h ; also: mode 002h *
	dw     132,     25,     16,     014h +  00000h ; also: mode 055h
	dw     132,     43,     16,     054h +  00000h
	dw     132,     50,     16,     014h +  00100h ; also: mode 055h *
	dw       0,      0,      0,     000h +  00000h


;--------------------------------------------------------------------------
; TABLE OF SUPPORTED GRAPHICS MODES
;       - keep sorted first by colors then by size
;       - end with an all 0 entry
;       - BIOS field = 0xff disables it
;       - fields:
;               width,  height, colors, BIOS#+  setup_procedure_index*256
;--------------------------------------------------------------------------
graphics_mode_table     label word
	dw      640,    200,      2,    006h +  00000h
	dw      640,    350,      2,    00fh +  00000h
	dw      640,    480,      2,    011h +  00000h

	dw      320,    200,      4,    005h +  00000h

	dw      320,    200,     16,    00dh +  00000h
	dw      640,    200,     16,    00eh +  00000h
	dw      640,    350,     16,    010h +  00000h
	dw      640,    480,     16,    012h +  00000h
	dw      800,    600,     16,    058h +  00000h ; also: mode 06ah
	dw     1024,    768,     16,    05dh +  00000h
	dw     1280,   1024,     16,	06ch +  00000h

	dw      320,    200,    256,    013h +  00000h
	dw      640,    480,    256,    05fh +  00000h
	dw      800,    600,    256,    05ch +  00000h
	dw     1024,    768,    256,    060h +  00000h
TwoMegMode1             label word
	dw     1280,   1024,    256,    06dh +  00000h ; requires 2 Mb !!!

	dw      640,    480,  32768,    066h +  00000h
	dw      800,    600,  32768,    067h +  00000h

	dw	320,	200, 0c010h,	06fh +	00000h
	dw	640,	480, 0c010h,    064h +  00000h 
	dw	800,	600, 0c010h,	065h +  00000h
TwoMegMode2             label word
	dw     1024,    768, 0c010h,    074h +  00000h ; requires 2 Mb !!!
; To use the 16M modes, see note above (BJW)
	dw	320,	200, 0c018h,	070h +	00000h
	dw      640,	480, 0c018h,	071h +  00000h
	dw        0,      0,      0,    000h +  00000h


;--------------------------------------------------------------------------
; TABLE OF SPECIAL SETUP PROCEDURES
;  You may need such procedures for:
;     -- reloading fonts on standard EGA or VGA for
;        higher resolution text modes
;     -- enable HiColor mode of some Super VGAs
;     -- Handle the parameter passing conventions of the VESA BIOS
;     -- put VGA into 256 color plane mode ("MODE X")
;     -- etc...
;  There should be one entry in the table for every non-zero
;  'setup_procedure_index' in the text and graphics mode tables.
;  The first entry in the table belongs to index 100h, and so on.
;  The special setup procedure is invoked via a near call.
;
;  Entry: DI=address of the mode record from the text or graphics
;         table to set up.
;
;  Exit:  Adapter configured
;         BX=driver mode word as it should be returned by the mode set
;            routine. Typically it involves picking up the mode word
;            from the header and OR-ing in the appropriate bitplane mode
;            bitfield. (This is not needed for text modes)
;         AX, CX, DX, SI can be trashed, PRESERVE DI!!!!
;
;  NOTE: This runs in real mode, but don't mess with the segment registers.
;--------------------------------------------------------------------------
special_setup_table     label word
	dw      offset  VGA_50row_mode_set

;
; Routine to set up VGA 50 row mode
; interface is described above
;
VGA_50row_mode_set      proc    near
	mov     al,[di+6]               ; set 40x25 or 80x25 or 132x25 mode
	xor     ah,ah
	int     10h
	xor     bx,bx
	mov     ax,1112h                ; load 8x8 font
	int     10h
	ret
VGA_50row_mode_set      endp


;--------------------------------------------------------------------------
; DRIVER INIT ROUTINE
;  called once after the driver is loaded
;  may do one or more of the followings:
;    - check for proper board type
;    - check amount of RAM on board, and:
;       -- update word in header to reflect correct amount
;       -- disable modes in the tables for which there is not enough RAM
;    - check for special equipment (HiColor DAC, etc...)
;
;  Entry: nothing
;
;  Exit:  AX=status:
;          non-zero: OK,
;          0: something went wrong (e.g. wrong adapter, etc..)
;         BX,CX,DX may be trashed
;
;  NOTE: This runs in real mode, but don't mess with the segment registers.
;--------------------------------------------------------------------------
driver_init_routine     proc    far
        mov     ah,12h
        mov     bl,85h
        int     10h                     ; get number of 64k banks
        cmp     al,24                   ; at least 24 banks required for
        jae     EndIni                  ;    1024x768x64k and 1280x1024x256
        mov     bx,offset TwoMegMode1   ; not enough memory, so:
        mov     BYTE PTR [bx+6],0ffh    ;    disable 1280x1024x256
        mov     bx,offset TwoMegMode2
        mov     BYTE PTR [bx+6],0ffh    ;    disable 1024x768x64k
EndIni: mov     ax,1
        ret
driver_init_routine     endp


;--------------------------------------------------------------------------
; MODE SET ROUTINE
;  sets up a text or graphics mode as close as possible to the one
;  reguested by the user with regard to number of colors and size.
;
;  Entry: AX=mode selection
;     0 = 80x25 text
;     1 = default text
;     2 = text CX cols by DX rows
;     3 = biggest text
;     4 = 320x200 graphics
;     5 = default graphics
;     6 = graphics CX width by DX height
;     7 = biggest non-interlaced graphics
;     8 = biggest graphics
;     9 = graphics BX colors, CX width by DX height
;
;  Exit: BX=driver mode flag
;        CX=width (in pixels or characters)
;        DX=height
;
;  NOTE: This runs in real mode, but don't mess with the segment registers.
;        YOU SHOULD NOT NEED TO CHANGE THIS ROUTINE AS IT IS PRETTY
;        MUCH TABLE DRIVEN
;--------------------------------------------------------------------------
mode_set_routine        proc    far
	push    ds
	push    di
	push    si
	mov     si,cs
	mov     ds,si
	cmp     ax,9
	jbe     DoIt
	jmp     Exit
DoIt:   add     ax,ax
	mov     si,ax
	jmp     WORD PTR mode_set_table[si]
mode_set_table  label   word
	dw      offset mode_0
	dw      offset mode_1
	dw      offset mode_2
	dw      offset mode_3
	dw      offset mode_4
	dw      offset mode_5
	dw      offset mode_6
	dw      offset mode_7
	dw      offset mode_8
	dw      offset mode_9
mode_0: mov     si,offset text_mode_table       ; 80x25 text
	mov     bx,def_nc
	mov     cx,80
	mov     dx,25
	jmp     Lookup
mode_1: mov     si,offset text_mode_table       ; default text
	mov     bx,def_nc
	mov     cx,def_tw
	mov     dx,def_th
	jmp     Lookup
mode_2: mov     si,offset text_mode_table       ; CX*DX text
	mov     bx,def_nc
	jmp     Lookup
mode_3: mov     si,offset text_mode_table       ; biggest text
	mov     bx,def_nc
	mov     cx,Max_TW
	mov     dx,Max_TH
	jmp     Lookup
mode_4: mov     si,offset graphics_mode_table   ; 320x200 graphics
	mov     bx,def_nc
	mov     cx,320
	mov     dx,200
	jmp     Lookup
mode_5: mov     si,offset graphics_mode_table   ; default graphics
	mov     bx,def_nc
	mov     cx,def_gw
	mov     dx,def_gh
	jmp     Lookup
mode_6: mov     si,offset graphics_mode_table   ; CX*DX graphics
	mov     bx,def_nc
	jmp     Lookup
mode_7: mov     si,offset graphics_mode_table   ; biggest non-interlaced gr
	mov     bx,def_nc
	mov     cx,Max_GWn
	mov     dx,Max_GHn
	jmp     Lookup
mode_8: mov     si,offset graphics_mode_table   ; biggest graphics
	mov     bx,def_nc
	mov     cx,Max_GW
	mov     dx,Max_GH
	jmp     Lookup
mode_9: mov     si,offset graphics_mode_table   ; CX*DX graphics w/ BX colors
;
; At this point:
;   SI points to the table to search (text or graphics)
;   BX has colors
;   CX has width
;   DX has height
;
Lookup: xor     ax,ax                           ; last color number seen
Find_C: cmp     [si+4],ax                       ; last color number == this?
	je      Same_C
	jb      Prev_C                          ; end of table -- use last color
	cmp     BYTE PTR [si+6],0ffh            ; valid entry ?
	je      Prev_C                          ; not -- use last color
	mov     ax,[si+4]                       ; record color number
	mov     di,si                           ; start of entries w/ this color
	cmp     ax,bx                           ; enough colors ?
	jae     Find_S
Same_C: add     si,8
	jmp     Find_C
Prev_C: or      ax,ax                           ; found any color at all?
	je      Exit
;
; At this point:
;   DI points into the table to the first entry with the desired color
;      number (either it has enough colors or it is the highest color
;      number supported by the driver). Additionally, at least the
;      first (= smallest size) entry for this color is valid (has a
;      valid BIOS number).
;   AX has the color number adjusted for the driver
;   CX has width
;   DX has height
;
Find_S: cmp     [di+4],ax                       ; still the same color #?
	jne     Prev_S
	cmp     BYTE PTR [di+6],0ffh            ; valid entry ?
	je      Prev_S
	cmp     [di],cx
	jb      Next_S
	cmp     [di+2],dx
	jae     GotIt
Next_S: add     di,8
	jmp     Find_S
Prev_S: sub     di,8
;
; At this point:
;   DI points to the table entry we want to set up
;
GotIt:  mov     ax,[di+6]                       ; BIOS mode number
	or      ah,ah                           ; special ?
	je      doBIOS
	mov     al,ah
	xor     ah,ah
	dec     ax
	add     ax,ax
	mov     si,ax
	call    WORD PTR special_setup_table[si]
	jmp     RetVal
doBIOS: int     10h
	mov     bx,GRD_1_PLANE
	cmp     WORD PTR [di+4],2               ; 2 colors ?
	je      doFLAG
	mov     bx,GRD_4_PLANES
	cmp     WORD PTR [di+4],16              ; 16 colors ?
	je      doFLAG
	mov     bx,GRD_8_PLANES
	cmp     WORD PTR [di+4],256             ; 256 colors ?
	je      doFLAG
	mov     bx,GRD_16_PLANES
	cmp     WORD PTR [di+4],32768           ; 32K colors ?
	je      doFLAG
	mov     bx,GRD_16x_PLANES
	cmp     WORD PTR [di+4],0c010h          ; 64K colors ?
	je      doFLAG
	mov	bx,GRD_24_PLANES
	cmp	WORD PTR [di+4],0c018h          ; 16M colors ?
	je 	doFLAG
	mov     bx,GRD_PLANE_MASK               ; something is wrong!!
doFLAG: or      bx,mode_W
RetVal: mov     cx,[di]
	mov     dx,[di+2]
Exit:   pop     si
	pop     di
	pop     ds
	ret
mode_set_routine        endp


;--------------------------------------------------------------------------
; PAGING ROUTINE
;
;  Entry: AH=read page
;         AL=write page
;
;  Exit: VGA configured.
;        AX,BX,CX,DX,SI,DI may be trashed
;
;  NOTE: This runs in protected mode!  Don't mess with the segment registers!
;        This code must be relocatable and may not reference any data!
;--------------------------------------------------------------------------
	assume  ds:nothing, es:nothing

paging_routine  proc    far
	mov	cl,4
	shl     ah,cl
	mov     dx,03ceh
	mov     al,9
	out     dx,al
	inc     dx
	mov     al,ah
	out     dx,al

	mov     al,8            ; reconfig GR CTRL port for mask writes
	dec     dx
	out     dx,al
	ret
paging_routine  endp


cseg    ends
	end
