// ============================================================================================
/*
* vgabios.c
*/
// ============================================================================================
//
// Copyright (C) 2001-2008 the LGPL VGABios developers Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// ============================================================================================
//
// This VGA Bios is specific to the plex86/bochs Emulated VGA card.
// You can NOT drive any physical vga card with it.
//
// ============================================================================================
//
// This file contains code ripped from :
// - rombios.c of plex86
//
// This VGA Bios contains fonts from :
// - fntcol16.zip (c) by Joseph Gil avalable at :
// ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
// These fonts are public domain
//
// This VGA Bios is based on information taken from :
// - Kevin Lawton's vga card emulation for bochs/plex86
// - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
// - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
// - Michael Abrash's Graphics Programming Black Book
// - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
// - DOSEMU 1.0.1 source code for several tables values and formulas
//
// Thanks for patches, comments and ideas to :
// - techt@pikeonline.net
//
// ============================================================================================
#include "vgabios.h"
#ifdef VBE
#include "vbe.h"
#endif
#define USE_BX_INFO
/* Declares */
static Bit8u read_byte();
static Bit16u read_word();
static void write_byte();
static void write_word();
static Bit8u inb();
static Bit16u inw();
static void outb();
static void outw();
static Bit16u get_SS();
// Output
static void printf();
static void unimplemented();
static void unknown();
static Bit8u find_vga_entry();
static void memsetb();
static void memsetw();
static void memcpyb();
static void memcpyw();
static void biosfn_set_video_mode();
static void biosfn_set_cursor_shape();
static void biosfn_set_cursor_pos();
static void biosfn_get_cursor_pos();
static void biosfn_set_active_page();
static void biosfn_scroll();
static void biosfn_read_char_attr();
static void biosfn_write_char_attr();
static void biosfn_write_char_only();
static void biosfn_write_pixel();
static void biosfn_read_pixel();
static void biosfn_write_teletype();
static void biosfn_perform_gray_scale_summing();
static void biosfn_load_text_user_pat();
static void biosfn_load_text_8_14_pat();
static void biosfn_load_text_8_8_pat();
static void biosfn_load_text_8_16_pat();
static void biosfn_load_gfx_8_8_chars();
static void biosfn_load_gfx_user_chars();
static void biosfn_load_gfx_8_14_chars();
static void biosfn_load_gfx_8_8_dd_chars();
static void biosfn_load_gfx_8_16_chars();
static void biosfn_get_font_info();
static void biosfn_alternate_prtsc();
static void biosfn_switch_video_interface();
static void biosfn_enable_video_refresh_control();
static void biosfn_write_string();
static void biosfn_read_state_info();
static void biosfn_read_video_state_size();
static Bit16u biosfn_save_video_state();
static Bit16u biosfn_restore_video_state();
extern Bit8u video_save_pointer_table[];
// This is for compiling with gcc2 and gcc3
#define ASM_START #asm
#define ASM_END #endasm
ASM_START
MACRO SET_INT_VECTOR
push ds
xor ax, ax
mov ds, ax
mov ax, ?3
mov ?1*4, ax
mov ax, ?2
mov ?1*4+2, ax
pop ds
MEND
ASM_END
ASM_START
.text
.rom
.org 0
use16 386
vgabios_start:
.byte 0x55, 0xaa /* BIOS signature, required for BIOS extensions */
.byte 0x40 /* BIOS extension length in units of 512 bytes */
vgabios_entry_point:
jmp vgabios_init_func
#ifdef PCIBIOS
.org 0x18
.word vgabios_pci_data
#endif
// Info from Bart Oldeman
.org 0x1e
.ascii "IBM"
.byte 0x00
vgabios_name:
.ascii "Plex86/Bochs VGABios"
#ifdef PCIBIOS
.ascii " (PCI)"
#endif
.ascii " "
.byte 0x00
vgabios_version:
#ifndef VGABIOS_VERS
.ascii "current-cvs"
#else
.ascii VGABIOS_VERS
#endif
.ascii " "
vgabios_date:
.ascii VGABIOS_DATE
.byte 0x0a,0x0d
.byte 0x00
vgabios_copyright:
.ascii "(C) 2008 the LGPL VGABios developers Team"
.byte 0x0a,0x0d
.byte 0x00
vgabios_license:
.ascii "This VGA/VBE Bios is released under the GNU LGPL"
.byte 0x0a,0x0d
.byte 0x0a,0x0d
.byte 0x00
vgabios_website:
.ascii "Please visit :"
.byte 0x0a,0x0d
;;.ascii " . http://www.plex86.org"
;;.byte 0x0a,0x0d
.ascii " . http://bochs.sourceforge.net"
.byte 0x0a,0x0d
.ascii " . http://www.nongnu.org/vgabios"
.byte 0x0a,0x0d
.byte 0x0a,0x0d
.byte 0x00
#ifdef PCIBIOS
vgabios_pci_data:
.ascii "PCIR"
#ifdef CIRRUS
.word 0x1013
.word 0x00b8 // CLGD5446
#else
#error "Unknown PCI vendor and device id"
#endif
.word 0 // reserved
.word 0x18 // dlen
.byte 0 // revision
.byte 0x0 // class,hi: vga display
.word 0x300 // class,lo: vga display
.word 0x40 // bios size
.word 1 // revision
.byte 0 // intel x86 data
.byte 0x80 // last image
.word 0 // reserved
#endif
;; ============================================================================================
;;
;; Init Entry point
;;
;; ============================================================================================
vgabios_init_func:
;; init vga card
call init_vga_card
;; init basic bios vars
call init_bios_area
#ifdef VBE
;; init vbe functions
call vbe_init
#endif
;; set int10 vect
SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler)
#ifdef CIRRUS
call cirrus_init
#endif
;; display splash screen
call _display_splash_screen
;; init video mode and clear the screen
mov ax,#0x0003
int #0x10
;; show info
call _display_info
#ifdef VBE
;; show vbe info
call vbe_display_info
#endif
#ifdef CIRRUS
;; show cirrus info
call cirrus_display_info
#endif
retf
ASM_END
/*
* int10 handled here
*/
ASM_START
vgabios_int10_handler:
pushf
#ifdef DEBUG
push es
push ds
pusha
mov bx, #0xc000
mov ds, bx
call _int10_debugmsg
popa
pop ds
pop es
#endif
cmp ah, #0x0f
jne int10_test_1A
call biosfn_get_video_mode
jmp int10_end
int10_test_1A:
cmp ah, #0x1a
jne int10_test_0B
call biosfn_group_1A
jmp int10_end
int10_test_0B:
cmp ah, #0x0b
jne int10_test_1103
call biosfn_group_0B
jmp int10_end
int10_test_1103:
cmp ax, #0x1103
jne int10_test_12
call biosfn_set_text_block_specifier
jmp int10_end
int10_test_12:
cmp ah, #0x12
jne int10_test_101B
cmp bl, #0x10
jne int10_test_BL30
call biosfn_get_ega_info
jmp int10_end
int10_test_BL30:
cmp bl, #0x30
jne int10_test_BL31
call biosfn_select_vert_res
jmp int10_end
int10_test_BL31:
cmp bl, #0x31
jne int10_test_BL32
call biosfn_enable_default_palette_loading
jmp int10_end
int10_test_BL32:
cmp bl, #0x32
jne int10_test_BL33
call biosfn_enable_video_addressing
jmp int10_end
int10_test_BL33:
cmp bl, #0x33
jne int10_test_BL34
call biosfn_enable_grayscale_summing
jmp int10_end
int10_test_BL34:
cmp bl, #0x34
jne int10_normal
call biosfn_enable_cursor_emulation
jmp int10_end
int10_test_101B:
cmp ax, #0x101b
je int10_normal
cmp ah, #0x10
#ifndef VBE
jne int10_normal
#else
jne int10_test_4F
#endif
call biosfn_group_10
jmp int10_end
#ifdef VBE
int10_test_4F:
cmp ah, #0x4f
jne int10_normal
cmp al, #0x03
jne int10_test_vbe_05
call vbe_biosfn_return_current_mode
jmp int10_end
int10_test_vbe_05:
cmp al, #0x05
jne int10_test_vbe_06
call vbe_biosfn_display_window_control
jmp int10_end
int10_test_vbe_06:
cmp al, #0x06
jne int10_test_vbe_07
call vbe_biosfn_set_get_logical_scan_line_length
jmp int10_end
int10_test_vbe_07:
cmp al, #0x07
jne int10_test_vbe_08
call vbe_biosfn_set_get_display_start
jmp int10_end
int10_test_vbe_08:
cmp al, #0x08
jne int10_test_vbe_0A
call vbe_biosfn_set_get_dac_palette_format
jmp int10_end
int10_test_vbe_0A:
cmp al, #0x0A
jne int10_normal
call vbe_biosfn_return_protected_mode_interface
jmp int10_end
#endif
int10_normal:
push es
push ds
pusha
;; We have to set ds to access the right data segment
mov bx, #0xc000
mov ds, bx
call _int10_func
popa
pop ds
pop es
int10_end:
popf
iret
ASM_END
#include "vgatables.h"
#include "vgafonts.h"
/*
* Boot time harware inits
*/
ASM_START
init_vga_card:
;; switch to color mode and enable CPU access 480 lines
mov dx, #0x3C2
mov al, #0xC3
outb dx,al
;; more than 64k 3C4/04
mov dx, #0x3C4
mov al, #0x04
outb dx,al
mov dx, #0x3C5
mov al, #0x02
outb dx,al
#if defined(USE_BX_INFO) || defined(DEBUG)
mov bx, #msg_vga_init
push bx
call _printf
inc sp
inc sp
#endif
ret
#if defined(USE_BX_INFO) || defined(DEBUG)
msg_vga_init:
.ascii "VGABios $Id$"
.byte 0x0d,0x0a,0x00
#endif
ASM_END
// --------------------------------------------------------------------------------------------
/*
* Boot time bios area inits
*/
ASM_START
init_bios_area:
push ds
mov ax, # BIOSMEM_SEG
mov ds, ax
;; init detected hardware BIOS Area
mov bx, # BIOSMEM_INITIAL_MODE
mov ax, [bx]
and ax, #0xffcf
;; set 80x25 color (not clear from RBIL but usual)
or ax, #0x0020
mov [bx], ax
;; Just for the first int10 find its children
;; the default char height
mov bx, # BIOSMEM_CHAR_HEIGHT
mov al, #0x10
mov [bx], al
;; Clear the screen
mov bx, # BIOSMEM_VIDEO_CTL
mov al, #0x60
mov [bx], al
;; Set the basic screen we have
mov bx, # BIOSMEM_SWITCHES
mov al, #0xf9
mov [bx], al
;; Set the basic modeset options
mov bx, # BIOSMEM_MODESET_CTL
mov al, #0x51
mov [bx], al
;; Set the default MSR
mov bx, # BIOSMEM_CURRENT_MSR
mov al, #0x09
mov [bx], al
pop ds
ret
_video_save_pointer_table:
.word _video_param_table
.word 0xc000
.word 0 /* XXX: fill it */
.word 0
.word 0 /* XXX: fill it */
.word 0
.word 0 /* XXX: fill it */
.word 0
.word 0 /* XXX: fill it */
.word 0
.word 0 /* XXX: fill it */
.word 0
.word 0 /* XXX: fill it */
.word 0
ASM_END
// --------------------------------------------------------------------------------------------
/*
* Boot time Splash screen
*/
static void display_splash_screen()
{
}
// --------------------------------------------------------------------------------------------
/*
* Tell who we are
*/
static void display_info()
{
ASM_START
mov ax,#0xc000
mov ds,ax
mov si,#vgabios_name
call _display_string
mov si,#vgabios_version
call _display_string
;;mov si,#vgabios_copyright
;;call _display_string
;;mov si,#crlf
;;call _display_string
mov si,#vgabios_license
call _display_string
mov si,#vgabios_website
call _display_string
ASM_END
}
static void display_string()
{
// Get length of string
ASM_START
mov ax,ds
mov es,ax
mov di,si
xor cx,cx
not cx
xor al,al
cld
repne
scasb
not cx
dec cx
push cx
mov ax,#0x0300
mov bx,#0x0000
int #0x10
pop cx
mov ax,#0x1301
mov bx,#0x000b
mov bp,si
int #0x10
ASM_END
}
// --------------------------------------------------------------------------------------------
#ifdef DEBUG
static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
{
// 0E is write char...
if(GET_AH()!=0x0E)
printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
}
#endif
// --------------------------------------------------------------------------------------------
/*
* int10 main dispatcher
*/
static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
{
// BIOS functions
switch(GET_AH())
{
case 0x00:
biosfn_set_video_mode(GET_AL());
switch(GET_AL()&0x7F)
{case 6:
SET_AL(0x3F);
break;
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 7:
SET_AL(0x30);
break;
default:
SET_AL(0x20);
}
break;
case 0x01:
biosfn_set_cursor_shape(GET_CH(),GET_CL());
break;
case 0x02:
biosfn_set_cursor_pos(GET_BH(),DX);
break;
case 0x03:
biosfn_get_cursor_pos(GET_BH(),&CX,&DX);
break;
case 0x04:
// Read light pen pos (unimplemented)
#ifdef DEBUG
unimplemented();
#endif
AX=0x00;
BX=0x00;
CX=0x00;
DX=0x00;
break;
case 0x05:
biosfn_set_active_page(GET_AL());
break;
case 0x06:
biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
break;
case 0x07:
biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
break;
case 0x08:
biosfn_read_char_attr(GET_BH(),&AX);
break;
case 0x09:
biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
break;
case 0x0A:
biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
break;
case 0x0C:
biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
break;
case 0x0D:
biosfn_read_pixel(GET_BH(),CX,DX,&AX);
break;
case 0x0E:
// Ralf Brown Interrupt list is WRONG on bh(page)
// We do output only on the current page !
biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
break;
case 0x10:
// All other functions of group AH=0x10 rewritten in assembler
biosfn_perform_gray_scale_summing(BX,CX);
break;
case 0x11:
switch(GET_AL())
{
case 0x00:
case 0x10:
biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
break;
case 0x01:
case 0x11:
biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
break;
case 0x02:
case 0x12:
biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
break;
case 0x04:
case 0x14:
biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
break;
case 0x20:
biosfn_load_gfx_8_8_chars(ES,BP);
break;
case 0x21:
biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
break;
case 0x22:
biosfn_load_gfx_8_14_chars(GET_BL());
break;
case 0x23:
biosfn_load_gfx_8_8_dd_chars(GET_BL());
break;
case 0x24:
biosfn_load_gfx_8_16_chars(GET_BL());
break;
case 0x30:
biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX);
break;
#ifdef DEBUG
default:
unknown();
#endif
}
break;
case 0x12:
switch(GET_BL())
{
case 0x20:
biosfn_alternate_prtsc();
break;
case 0x35:
biosfn_switch_video_interface(GET_AL(),ES,DX);
SET_AL(0x12);
break;
case 0x36:
biosfn_enable_video_refresh_control(GET_AL());
SET_AL(0x12);
break;
#ifdef DEBUG
default:
unknown();
#endif
}
break;
case 0x13:
biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
break;
case 0x1B:
biosfn_read_state_info(BX,ES,DI);
SET_AL(0x1B);
break;
case 0x1C:
switch(GET_AL())
{
case 0x00:
biosfn_read_video_state_size(CX,&BX);
break;
case 0x01:
biosfn_save_video_state(CX,ES,BX);
break;
case 0x02:
biosfn_restore_video_state(CX,ES,BX);
break;
#ifdef DEBUG
default:
unknown();
#endif
}
SET_AL(0x1C);
break;
#ifdef VBE
case 0x4f:
if (vbe_has_vbe_display()) {
switch(GET_AL())
{
case 0x00:
vbe_biosfn_return_controller_information(&AX,ES,DI);
break;
case 0x01:
vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
break;
case 0x02:
vbe_biosfn_set_mode(&AX,BX,ES,DI);
break;
case 0x04:
vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
break;
case 0x09:
//FIXME
#ifdef DEBUG
unimplemented();
#endif
// function failed
AX=0x100;
break;
case 0x0A:
//FIXME
#ifdef DEBUG
unimplemented();
#endif
// function failed
AX=0x100;
break;
default:
#ifdef DEBUG
unknown();
#endif
// function failed
AX=0x100;
}
}
else {
// No VBE display
AX=0x0100;
}
break;
#endif
#ifdef DEBUG
default:
unknown();
#endif
}
}
// ============================================================================================
//
// BIOS functions
//
// ============================================================================================
static void biosfn_set_video_mode(mode) Bit8u mode;
{// mode: Bit 7 is 1 if no clear screen
// Should we clear the screen ?
Bit8u noclearmem=mode&0x80;
Bit8u line,mmask,*palette,vpti;
Bit16u i,twidth,theightm1,cheight;
Bit8u modeset_ctl,video_ctl,vga_switches;
Bit16u crtc_addr;
#ifdef VBE
if (vbe_has_vbe_display()) {
dispi_set_enable(VBE_DISPI_DISABLED);
}
#endif // def VBE
// The real mode
mode=mode&0x7f;
// find the entry in the video modes
line=find_vga_entry(mode);
#ifdef DEBUG
printf("mode search %02x found line %02x\n",mode,line);
#endif
if(line==0xFF)
return;
vpti=line_to_vpti[line];
twidth=video_param_table[vpti].twidth;
theightm1=video_param_table[vpti].theightm1;
cheight=video_param_table[vpti].cheight;
// Read the bios vga control
video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
// Read the bios vga switches
vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
// Read the bios mode set control
modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
// Then we know the number of lines
// FIXME
// if palette loading (bit 3 of modeset ctl = 0)
if((modeset_ctl&0x08)==0)
{// Set the PEL mask
outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
// Set the whole dac always, from 0
outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
// From which palette
switch(vga_modes[line].dacmodel)
{case 0:
palette=&palette0;
break;
case 1:
palette=&palette1;
break;
case 2:
palette=&palette2;
break;
case 3:
palette=&palette3;
break;
}
// Always 256*3 values
for(i=0;i<0x0100;i++)
{if(i<=dac_regs[vga_modes[line].dacmodel])
{outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
}
else
{outb(VGAREG_DAC_DATA,0);
outb(VGAREG_DAC_DATA,0);
outb(VGAREG_DAC_DATA,0);
}
}
if((modeset_ctl&0x02)==0x02)
{
biosfn_perform_gray_scale_summing(0x00, 0x100);
}
}
// Reset Attribute Ctl flip-flop
inb(VGAREG_ACTL_RESET);
// Set Attribute Ctl
for(i=0;i<=0x13;i++)
{outb(VGAREG_ACTL_ADDRESS,i);
outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
}
outb(VGAREG_ACTL_ADDRESS,0x14);
outb(VGAREG_ACTL_WRITE_DATA,0x00);
// Set Sequencer Ctl
outb(VGAREG_SEQU_ADDRESS,0);
outb(VGAREG_SEQU_DATA,0x03);
for(i=1;i<=4;i++)
{outb(VGAREG_SEQU_ADDRESS,i);
outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
}
// Set Grafx Ctl
for(i=0;i<=8;i++)
{outb(VGAREG_GRDC_ADDRESS,i);
outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
}
// Set CRTC address VGA or MDA
crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
// Disable CRTC write protection
outw(crtc_addr,0x0011);
// Set CRTC regs
for(i=0;i<=0x18;i++)
{outb(crtc_addr,i);
outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
}
// Set the misc register
outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
// Enable video
outb(VGAREG_ACTL_ADDRESS,0x20);
inb(VGAREG_ACTL_RESET);
if(noclearmem==0x00)
{
if(vga_modes[line].class==TEXT)
{
memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
}
else
{
if(mode<0x0d)
{
memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
}
else
{
outb( VGAREG_SEQU_ADDRESS, 0x02 );
mmask = inb( VGAREG_SEQU_DATA );
outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
outb( VGAREG_SEQU_DATA, mmask );
}
}
}
// Set the BIOS mem
write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l);
write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
// FIXME We nearly have the good tables. to be reworked
write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table);
write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000);
// FIXME
write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
// Set cursor shape
if(vga_modes[line].class==TEXT)
{
biosfn_set_cursor_shape(0x06,0x07);
}
// Set cursor pos for page 0..7
for(i=0;i<8;i++)
biosfn_set_cursor_pos(i,0x0000);
// Set active page 0
biosfn_set_active_page(0x00);
// Write the fonts in memory
if(vga_modes[line].class==TEXT)
{
ASM_START
;; copy and activate 8x16 font
mov ax, #0x1104
mov bl, #0x00
int #0x10
mov ax, #0x1103
mov bl, #0x00
int #0x10
ASM_END
}
// Set the ints 0x1F and 0x43
ASM_START
SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
ASM_END
switch(cheight)
{case 8:
ASM_START
SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
ASM_END
break;
case 14:
ASM_START
SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
ASM_END
break;
case 16:
ASM_START
SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
ASM_END
break;
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_set_cursor_shape (CH,CL)
Bit8u CH;Bit8u CL;
{Bit16u cheight,curs,crtc_addr;
Bit8u modeset_ctl;
CH&=0x3f;
CL&=0x1f;
curs=(CH<<8)+CL;
write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs);
modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20))
{
if(CL!=(CH+1))
{
CH = ((CH+1) * cheight / 8) -1;
}
else
{
CH = ((CL+1) * cheight / 8) - 2;
}
CL = ((CL+1) * cheight / 8) - 1;
}
// CTRC regs 0x0a and 0x0b
crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
outb(crtc_addr,0x0a);
outb(crtc_addr+1,CH);
outb(crtc_addr,0x0b);
outb(crtc_addr+1,CL);
}
// --------------------------------------------------------------------------------------------
static void biosfn_set_cursor_pos (page, cursor)
Bit8u page;Bit16u cursor;
{
Bit8u xcurs,ycurs,current;
Bit16u nbcols,nbrows,address,crtc_addr;
// Should not happen...
if(page>7)return;
// Bios cursor pos
write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
// Set the hardware cursor
current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
if(page==current)
{
// Get the dimensions
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
// Calculate the address knowing nbcols nbrows and page num
address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
// CRTC regs 0x0e and 0x0f
crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
outb(crtc_addr,0x0e);
outb(crtc_addr+1,(address&0xff00)>>8);
outb(crtc_addr,0x0f);
outb(crtc_addr+1,address&0x00ff);
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_get_cursor_pos (page,shape, pos)
Bit8u page;Bit16u *shape;Bit16u *pos;
{
Bit16u ss=get_SS();
// Default
write_word(ss, shape, 0);
write_word(ss, pos, 0);
if(page>7)return;
// FIXME should handle VGA 14/16 lines
write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE));
write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2));
}
// --------------------------------------------------------------------------------------------
static void biosfn_set_active_page (page)
Bit8u page;
{
Bit16u cursor,dummy,crtc_addr;
Bit16u nbcols,nbrows,address;
Bit8u mode,line;
if(page>7)return;
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
// Get pos curs pos for the right page
biosfn_get_cursor_pos(page,&dummy,&cursor);
if(vga_modes[line].class==TEXT)
{
// Get the dimensions
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
// Calculate the address knowing nbcols nbrows and page num
address=SCREEN_MEM_START(nbcols,nbrows,page);
write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
// Start address
address=SCREEN_IO_START(nbcols,nbrows,page);
}
else
{
address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l);
}
// CRTC regs 0x0c and 0x0d
crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
outb(crtc_addr,0x0c);
outb(crtc_addr+1,(address&0xff00)>>8);
outb(crtc_addr,0x0d);
outb(crtc_addr+1,address&0x00ff);
// And change the BIOS page
write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
#ifdef DEBUG
printf("Set active page %02x address %04x\n",page,address);
#endif
// Display the cursor, now the page is active
biosfn_set_cursor_pos(page,cursor);
}
// --------------------------------------------------------------------------------------------
static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
{
Bit16u src,dest;
Bit8u i;
src=ysrc*cheight*nbcols+xstart;
dest=ydest*cheight*nbcols+xstart;
outw(VGAREG_GRDC_ADDRESS, 0x0105);
for(i=0;i<cheight;i++)
{
memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
}
outw(VGAREG_GRDC_ADDRESS, 0x0005);
}
// --------------------------------------------------------------------------------------------
static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
{
Bit16u dest;
Bit8u i;
dest=ystart*cheight*nbcols+xstart;
outw(VGAREG_GRDC_ADDRESS, 0x0205);
for(i=0;i<cheight;i++)
{
memsetb(0xa000,dest+i*nbcols,attr,cols);
}
outw(VGAREG_GRDC_ADDRESS, 0x0005);
}
// --------------------------------------------------------------------------------------------
static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
{
Bit16u src,dest;
Bit8u i;
src=((ysrc*cheight*nbcols)>>1)+xstart;
dest=((ydest*cheight*nbcols)>>1)+xstart;
for(i=0;i<cheight;i++)
{
if (i & 1)
memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
else
memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
}
}
// --------------------------------------------------------------------------------------------
static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
{
Bit16u dest;
Bit8u i;
dest=((ystart*cheight*nbcols)>>1)+xstart;
for(i=0;i<cheight;i++)
{
if (i & 1)
memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
else
memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir;
{
// page == 0xFF if current
Bit8u mode,line,cheight,bpp,cols;
Bit16u nbcols,nbrows,i;
Bit16u address;
if(rul>rlr)return;
if(cul>clr)return;
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
// Get the dimensions
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
// Get the current page
if(page==0xFF)
page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
if(rlr>=nbrows)rlr=nbrows-1;
if(clr>=nbcols)clr=nbcols-1;
if(nblines>nbrows)nblines=0;
cols=clr-cul+1;
if(vga_modes[line].class==TEXT)
{
// Compute the address
address=SCREEN_MEM_START(nbcols,nbrows,page);
#ifdef DEBUG
printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
#endif
if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
{
memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols);
}
else
{// if Scroll up
if(dir==SCROLL_UP)
{for(i=rul;i<=rlr;i++)
{
if((i+nblines>rlr)||(nblines==0))
memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
else
memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
}
}
else
{for(i=rlr;i>=rul;i--)
{
if((i<rul+nblines)||(nblines==0))
memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
else
memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
if (i>rlr) break;
}
}
}
}
else
{
// FIXME gfx mode not complete
cheight=video_param_table[line_to_vpti[line]].cheight;
switch(vga_modes[line].memmodel)
{
case PLANAR4:
case PLANAR1:
if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
{
outw(VGAREG_GRDC_ADDRESS, 0x0205);
memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
outw(VGAREG_GRDC_ADDRESS, 0x0005);
}
else
{// if Scroll up
if(dir==SCROLL_UP)
{for(i=rul;i<=rlr;i++)
{
if((i+nblines>rlr)||(nblines==0))
vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
else
vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
}
}
else
{for(i=rlr;i>=rul;i--)
{
if((i<rul+nblines)||(nblines==0))
vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
else
vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
if (i>rlr) break;
}
}
}
break;
case CGA:
bpp=vga_modes[line].pixbits;
if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
{
memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
}
else
{
if(bpp==2)
{
cul<<=1;
cols<<=1;
nbcols<<=1;
}
// if Scroll up
if(dir==SCROLL_UP)
{for(i=rul;i<=rlr;i++)
{
if((i+nblines>rlr)||(nblines==0))
vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
else
vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
}
}
else
{for(i=rlr;i>=rul;i--)
{
if((i<rul+nblines)||(nblines==0))
vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
else
vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
if (i>rlr) break;
}
}
}
break;
#ifdef DEBUG
default:
printf("Scroll in graphics mode ");
unimplemented();
#endif
}
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_read_char_attr (page,car)
Bit8u page;Bit16u *car;
{Bit16u ss=get_SS();
Bit8u xcurs,ycurs,mode,line;
Bit16u nbcols,nbrows,address;
Bit16u cursor,dummy;
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
// Get the cursor pos for the page
biosfn_get_cursor_pos(page,&dummy,&cursor);
xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
// Get the dimensions
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
if(vga_modes[line].class==TEXT)
{
// Compute the address
address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
write_word(ss,car,read_word(vga_modes[line].sstart,address));
}
else
{
// FIXME gfx mode
#ifdef DEBUG
unimplemented();
#endif
}
}
// --------------------------------------------------------------------------------------------
static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight;
{
Bit8u i,j,mask;
Bit8u *fdata;
Bit16u addr,dest,src;
switch(cheight)
{case 14:
fdata = &vgafont14;
break;
case 16:
fdata = &vgafont16;
break;
default:
fdata = &vgafont8;
}
addr=xcurs+ycurs*cheight*nbcols;
src = car * cheight;
outw(VGAREG_SEQU_ADDRESS, 0x0f02);
outw(VGAREG_GRDC_ADDRESS, 0x0205);
if(attr&0x80)
{
outw(VGAREG_GRDC_ADDRESS, 0x1803);
}
else
{
outw(VGAREG_GRDC_ADDRESS, 0x0003);
}
for(i=0;i<cheight;i++)
{
dest=addr+i*nbcols;
for(j=0;j<8;j++)
{
mask=0x80>>j;
outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
read_byte(0xa000,dest);
if(fdata[src+i]&mask)
{
write_byte(0xa000,dest,attr&0x0f);
}
else
{
write_byte(0xa000,dest,0x00);
}
}
}
ASM_START
mov dx, # VGAREG_GRDC_ADDRESS
mov ax, #0xff08
out dx, ax
mov ax, #0x0005
out dx, ax
mov ax, #0x0003
out dx, ax
ASM_END
}
// --------------------------------------------------------------------------------------------
static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp;
{
Bit8u i,j,mask,data;
Bit8u *fdata;
Bit16u addr,dest,src;
fdata = &vgafont8;
addr=(xcurs*bpp)+ycurs*320;
src = car * 8;
for(i=0;i<8;i++)
{
dest=addr+(i>>1)*80;
if (i & 1) dest += 0x2000;
mask = 0x80;
if (bpp == 1)
{
if (attr & 0x80)
{
data = read_byte(0xb800,dest);
}
else
{
data = 0x00;
}
for(j=0;j<8;j++)
{
if (fdata[src+i] & mask)
{
if (attr & 0x80)
{
data ^= (attr & 0x01) << (7-j);
}
else
{
data |= (attr & 0x01) << (7-j);
}
}
mask >>= 1;
}
write_byte(0xb800,dest,data);
}
else
{
while (mask > 0)
{
if (attr & 0x80)
{
data = read_byte(0xb800,dest);
}
else
{
data = 0x00;
}
for(j=0;j<4;j++)
{
if (fdata[src+i] & mask)
{
if (attr & 0x80)
{
data ^= (attr & 0x03) << ((3-j)*2);
}
else
{
data |= (attr & 0x03) << ((3-j)*2);
}
}
mask >>= 1;
}
write_byte(0xb800,dest,data);
dest += 1;
}
}
}
}
// --------------------------------------------------------------------------------------------
static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;
{
Bit8u i,j,mask,data;
Bit8u *fdata;
Bit16u addr,dest,src;
fdata = &vgafont8;
addr=xcurs*8+ycurs*nbcols*64;
src = car * 8;
for(i=0;i<8;i++)
{
dest=addr+i*nbcols*8;
mask = 0x80;
for(j=0;j<8;j++)
{
data = 0x00;
if (fdata[src+i] & mask)
{
data = attr;
}
write_byte(0xa000,dest+j,data);
mask >>= 1;
}
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_write_char_attr (car,page,attr,count)
Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
{
Bit8u cheight,xcurs,ycurs,mode,line,bpp;
Bit16u nbcols,nbrows,address;
Bit16u cursor,dummy;
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
// Get the cursor pos for the page
biosfn_get_cursor_pos(page,&dummy,&cursor);
xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
// Get the dimensions
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
if(vga_modes[line].class==TEXT)
{
// Compute the address
address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
dummy=((Bit16u)attr<<8)+car;
memsetw(vga_modes[line].sstart,address,dummy,count);
}
else
{
// FIXME gfx mode not complete
cheight=video_param_table[line_to_vpti[line]].cheight;
bpp=vga_modes[line].pixbits;
while((count-->0) && (xcurs<nbcols))
{
switch(vga_modes[line].memmodel)
{
case PLANAR4:
case PLANAR1:
write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
break;
case CGA:
write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
break;
case LINEAR8:
write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
break;
#ifdef DEBUG
default:
unimplemented();
#endif
}
xcurs++;
}
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_write_char_only (car,page,attr,count)
Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
{
Bit8u cheight,xcurs,ycurs,mode,line,bpp;
Bit16u nbcols,nbrows,address;
Bit16u cursor,dummy;
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
// Get the cursor pos for the page
biosfn_get_cursor_pos(page,&dummy,&cursor);
xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
// Get the dimensions
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
if(vga_modes[line].class==TEXT)
{
// Compute the address
address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
while(count-->0)
{write_byte(vga_modes[line].sstart,address,car);
address+=2;
}
}
else
{
// FIXME gfx mode not complete
cheight=video_param_table[line_to_vpti[line]].cheight;
bpp=vga_modes[line].pixbits;
while((count-->0) && (xcurs<nbcols))
{
switch(vga_modes[line].memmodel)
{
case PLANAR4:
case PLANAR1:
write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
break;
case CGA:
write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
break;
case LINEAR8:
write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
break;
#ifdef DEBUG
default:
unimplemented();
#endif
}
xcurs++;
}
}
}
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_group_0B:
cmp bh, #0x00
je biosfn_set_border_color
cmp bh, #0x01
je biosfn_set_palette
#ifdef DEBUG
call _unknown
#endif
ret
biosfn_set_border_color:
push ax
push bx
push cx
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x00
out dx, al
mov al, bl
and al, #0x0f
test al, #0x08
jz set_low_border
add al, #0x08
set_low_border:
out dx, al
mov cl, #0x01
and bl, #0x10
set_intensity_loop:
mov dx, # VGAREG_ACTL_ADDRESS
mov al, cl
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
and al, #0xef
or al, bl
mov dx, # VGAREG_ACTL_ADDRESS
out dx, al
inc cl
cmp cl, #0x04
jne set_intensity_loop
mov al, #0x20
out dx, al
pop dx
pop cx
pop bx
pop ax
ret
biosfn_set_palette:
push ax
push bx
push cx
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov cl, #0x01
and bl, #0x01
set_cga_palette_loop:
mov dx, # VGAREG_ACTL_ADDRESS
mov al, cl
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
and al, #0xfe
or al, bl
mov dx, # VGAREG_ACTL_ADDRESS
out dx, al
inc cl
cmp cl, #0x04
jne set_cga_palette_loop
mov al, #0x20
out dx, al
pop dx
pop cx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
{
Bit8u mode,line,mask,attr,data;
Bit16u addr;
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
if(vga_modes[line].class==TEXT)return;
switch(vga_modes[line].memmodel)
{
case PLANAR4:
case PLANAR1:
addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
mask = 0x80 >> (CX & 0x07);
outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
outw(VGAREG_GRDC_ADDRESS, 0x0205);
data = read_byte(0xa000,addr);
if (AL & 0x80)
{
outw(VGAREG_GRDC_ADDRESS, 0x1803);
}
write_byte(0xa000,addr,AL);
ASM_START
mov dx, # VGAREG_GRDC_ADDRESS
mov ax, #0xff08
out dx, ax
mov ax, #0x0005
out dx, ax
mov ax, #0x0003
out dx, ax
ASM_END
break;
case CGA:
if(vga_modes[line].pixbits==2)
{
addr=(CX>>2)+(DX>>1)*80;
}
else
{
addr=(CX>>3)+(DX>>1)*80;
}
if (DX & 1) addr += 0x2000;
data = read_byte(0xb800,addr);
if(vga_modes[line].pixbits==2)
{
attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
mask = 0x03 << ((3 - (CX & 0x03)) * 2);
}
else
{
attr = (AL & 0x01) << (7 - (CX & 0x07));
mask = 0x01 << (7 - (CX & 0x07));
}
if (AL & 0x80)
{
data ^= attr;
}
else
{
data &= ~mask;
data |= attr;
}
write_byte(0xb800,addr,data);
break;
case LINEAR8:
addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
write_byte(0xa000,addr,AL);
break;
#ifdef DEBUG
default:
unimplemented();
#endif
}
}
// --------------------------------------------------------------------------------------------
static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX;
{
Bit8u mode,line,mask,attr,data,i;
Bit16u addr;
Bit16u ss=get_SS();
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
if(vga_modes[line].class==TEXT)return;
switch(vga_modes[line].memmodel)
{
case PLANAR4:
case PLANAR1:
addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
mask = 0x80 >> (CX & 0x07);
attr = 0x00;
for(i=0;i<4;i++)
{
outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
data = read_byte(0xa000,addr) & mask;
if (data > 0) attr |= (0x01 << i);
}
break;
case CGA:
addr=(CX>>2)+(DX>>1)*80;
if (DX & 1) addr += 0x2000;
data = read_byte(0xb800,addr);
if(vga_modes[line].pixbits==2)
{
attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
}
else
{
attr = (data >> (7 - (CX & 0x07))) & 0x01;
}
break;
case LINEAR8:
addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
attr=read_byte(0xa000,addr);
break;
default:
#ifdef DEBUG
unimplemented();
#endif
attr = 0;
}
write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr);
}
// --------------------------------------------------------------------------------------------
static void biosfn_write_teletype (car, page, attr, flag)
Bit8u car;Bit8u page;Bit8u attr;Bit8u flag;
{// flag = WITH_ATTR / NO_ATTR
Bit8u cheight,xcurs,ycurs,mode,line,bpp;
Bit16u nbcols,nbrows,address;
Bit16u cursor,dummy;
// special case if page is 0xff, use current page
if(page==0xff)
page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
// Get the mode
mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
line=find_vga_entry(mode);
if(line==0xFF)return;
// Get the cursor pos for the page
biosfn_get_cursor_pos(page,&dummy,&cursor);
xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
// Get the dimensions
nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
switch(car)
{
case 7:
//FIXME should beep
break;
case 8:
if(xcurs>0)xcurs--;
break;
case '\r':
xcurs=0;
break;
case '\n':
ycurs++;
break;
case '\t':
do
{
biosfn_write_teletype(' ',page,attr,flag);
biosfn_get_cursor_pos(page,&dummy,&cursor);
xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
}while(xcurs%8==0);
break;
default:
if(vga_modes[line].class==TEXT)
{
// Compute the address
address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
// Write the char
write_byte(vga_modes[line].sstart,address,car);
if(flag==WITH_ATTR)
write_byte(vga_modes[line].sstart,address+1,attr);
}
else
{
// FIXME gfx mode not complete
cheight=video_param_table[line_to_vpti[line]].cheight;
bpp=vga_modes[line].pixbits;
switch(vga_modes[line].memmodel)
{
case PLANAR4:
case PLANAR1:
write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
break;
case CGA:
write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
break;
case LINEAR8:
write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
break;
#ifdef DEBUG
default:
unimplemented();
#endif
}
}
xcurs++;
}
// Do we need to wrap ?
if(xcurs==nbcols)
{xcurs=0;
ycurs++;
}
// Do we need to scroll ?
if(ycurs==nbrows)
{
if(vga_modes[line].class==TEXT)
{
address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
attr=read_byte(vga_modes[line].sstart,address+1);
biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
}
else
{
biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
}
ycurs-=1;
}
// Set the cursor for the page
cursor=ycurs; cursor<<=8; cursor+=xcurs;
biosfn_set_cursor_pos(page,cursor);
}
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_get_video_mode:
push ds
mov ax, # BIOSMEM_SEG
mov ds, ax
push bx
mov bx, # BIOSMEM_CURRENT_PAGE
mov al, [bx]
pop bx
mov bh, al
push bx
mov bx, # BIOSMEM_VIDEO_CTL
mov ah, [bx]
and ah, #0x80
mov bx, # BIOSMEM_CURRENT_MODE
mov al, [bx]
or al, ah
mov bx, # BIOSMEM_NB_COLS
mov ah, [bx]
pop bx
pop ds
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_group_10:
cmp al, #0x00
jne int10_test_1001
jmp biosfn_set_single_palette_reg
int10_test_1001:
cmp al, #0x01
jne int10_test_1002
jmp biosfn_set_overscan_border_color
int10_test_1002:
cmp al, #0x02
jne int10_test_1003
jmp biosfn_set_all_palette_reg
int10_test_1003:
cmp al, #0x03
jne int10_test_1007
jmp biosfn_toggle_intensity
int10_test_1007:
cmp al, #0x07
jne int10_test_1008
jmp biosfn_get_single_palette_reg
int10_test_1008:
cmp al, #0x08
jne int10_test_1009
jmp biosfn_read_overscan_border_color
int10_test_1009:
cmp al, #0x09
jne int10_test_1010
jmp biosfn_get_all_palette_reg
int10_test_1010:
cmp al, #0x10
jne int10_test_1012
jmp biosfn_set_single_dac_reg
int10_test_1012:
cmp al, #0x12
jne int10_test_1013
jmp biosfn_set_all_dac_reg
int10_test_1013:
cmp al, #0x13
jne int10_test_1015
jmp biosfn_select_video_dac_color_page
int10_test_1015:
cmp al, #0x15
jne int10_test_1017
jmp biosfn_read_single_dac_reg
int10_test_1017:
cmp al, #0x17
jne int10_test_1018
jmp biosfn_read_all_dac_reg
int10_test_1018:
cmp al, #0x18
jne int10_test_1019
jmp biosfn_set_pel_mask
int10_test_1019:
cmp al, #0x19
jne int10_test_101A
jmp biosfn_read_pel_mask
int10_test_101A:
cmp al, #0x1a
jne int10_group_10_unknown
jmp biosfn_read_video_dac_state
int10_group_10_unknown:
#ifdef DEBUG
call _unknown
#endif
ret
biosfn_set_single_palette_reg:
cmp bl, #0x14
ja no_actl_reg1
push ax
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, bl
out dx, al
mov al, bh
out dx, al
mov al, #0x20
out dx, al
pop dx
pop ax
no_actl_reg1:
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_set_overscan_border_color:
push bx
mov bl, #0x11
call biosfn_set_single_palette_reg
pop bx
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_set_all_palette_reg:
push ax
push bx
push cx
push dx
mov bx, dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov cl, #0x00
mov dx, # VGAREG_ACTL_ADDRESS
set_palette_loop:
mov al, cl
out dx, al
seg es
mov al, [bx]
out dx, al
inc bx
inc cl
cmp cl, #0x10
jne set_palette_loop
mov al, #0x11
out dx, al
seg es
mov al, [bx]
out dx, al
mov al, #0x20
out dx, al
pop dx
pop cx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_toggle_intensity:
push ax
push bx
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x10
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
and al, #0xf7
and bl, #0x01
shl bl, 3
or al, bl
mov dx, # VGAREG_ACTL_ADDRESS
out dx, al
mov al, #0x20
out dx, al
pop dx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_get_single_palette_reg:
cmp bl, #0x14
ja no_actl_reg2
push ax
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, bl
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
mov bh, al
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x20
out dx, al
pop dx
pop ax
no_actl_reg2:
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_read_overscan_border_color:
push ax
push bx
mov bl, #0x11
call biosfn_get_single_palette_reg
mov al, bh
pop bx
mov bh, al
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_get_all_palette_reg:
push ax
push bx
push cx
push dx
mov bx, dx
mov cl, #0x00
get_palette_loop:
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, cl
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
seg es
mov [bx], al
inc bx
inc cl
cmp cl, #0x10
jne get_palette_loop
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x11
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
seg es
mov [bx], al
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x20
out dx, al
pop dx
pop cx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_set_single_dac_reg:
push ax
push dx
mov dx, # VGAREG_DAC_WRITE_ADDRESS
mov al, bl
out dx, al
mov dx, # VGAREG_DAC_DATA
pop ax
push ax
mov al, ah
out dx, al
mov al, ch
out dx, al
mov al, cl
out dx, al
pop dx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_set_all_dac_reg:
push ax
push bx
push cx
push dx
mov dx, # VGAREG_DAC_WRITE_ADDRESS
mov al, bl
out dx, al
pop dx
push dx
mov bx, dx
mov dx, # VGAREG_DAC_DATA
set_dac_loop:
seg es
mov al, [bx]
out dx, al
inc bx
seg es
mov al, [bx]
out dx, al
inc bx
seg es
mov al, [bx]
out dx, al
inc bx
dec cx
jnz set_dac_loop
pop dx
pop cx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_select_video_dac_color_page:
push ax
push bx
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x10
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
and bl, #0x01
jnz set_dac_page
and al, #0x7f
shl bh, 7
or al, bh
mov dx, # VGAREG_ACTL_ADDRESS
out dx, al
jmp set_actl_normal
set_dac_page:
push ax
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x14
out dx, al
pop ax
and al, #0x80
jnz set_dac_16_page
shl bh, 2
set_dac_16_page:
and bh, #0x0f
mov al, bh
out dx, al
set_actl_normal:
mov al, #0x20
out dx, al
pop dx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_read_single_dac_reg:
push ax
push dx
mov dx, # VGAREG_DAC_READ_ADDRESS
mov al, bl
out dx, al
pop ax
mov ah, al
mov dx, # VGAREG_DAC_DATA
in al, dx
xchg al, ah
push ax
in al, dx
mov ch, al
in al, dx
mov cl, al
pop dx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_read_all_dac_reg:
push ax
push bx
push cx
push dx
mov dx, # VGAREG_DAC_READ_ADDRESS
mov al, bl
out dx, al
pop dx
push dx
mov bx, dx
mov dx, # VGAREG_DAC_DATA
read_dac_loop:
in al, dx
seg es
mov [bx], al
inc bx
in al, dx
seg es
mov [bx], al
inc bx
in al, dx
seg es
mov [bx], al
inc bx
dec cx
jnz read_dac_loop
pop dx
pop cx
pop bx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_set_pel_mask:
push ax
push dx
mov dx, # VGAREG_PEL_MASK
mov al, bl
out dx, al
pop dx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_read_pel_mask:
push ax
push dx
mov dx, # VGAREG_PEL_MASK
in al, dx
mov bl, al
pop dx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_read_video_dac_state:
push ax
push dx
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x10
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
mov bl, al
shr bl, 7
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x14
out dx, al
mov dx, # VGAREG_ACTL_READ_DATA
in al, dx
mov bh, al
and bh, #0x0f
test bl, #0x01
jnz get_dac_16_page
shr bh, 2
get_dac_16_page:
mov dx, # VGAREG_ACTL_RESET
in al, dx
mov dx, # VGAREG_ACTL_ADDRESS
mov al, #0x20
out dx, al
pop dx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
static void biosfn_perform_gray_scale_summing (start,count)
Bit16u start;Bit16u count;
{Bit8u r,g,b;
Bit16u i;
Bit16u index;
inb(VGAREG_ACTL_RESET);
outb(VGAREG_ACTL_ADDRESS,0x00);
for( index = 0; index < count; index++ )
{
// set read address and switch to read mode
outb(VGAREG_DAC_READ_ADDRESS,start);
// get 6-bit wide RGB data values
r=inb( VGAREG_DAC_DATA );
g=inb( VGAREG_DAC_DATA );
b=inb( VGAREG_DAC_DATA );
// intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
if(i>0x3f)i=0x3f;
// set write address and switch to write mode
outb(VGAREG_DAC_WRITE_ADDRESS,start);
// write new intensity value
outb( VGAREG_DAC_DATA, i&0xff );
outb( VGAREG_DAC_DATA, i&0xff );
outb( VGAREG_DAC_DATA, i&0xff );
start++;
}
inb(VGAREG_ACTL_RESET);
outb(VGAREG_ACTL_ADDRESS,0x20);
}
// --------------------------------------------------------------------------------------------
static void get_font_access()
{
ASM_START
mov dx, # VGAREG_SEQU_ADDRESS
mov ax, #0x0100
out dx, ax
mov ax, #0x0402
out dx, ax
mov ax, #0x0704
out dx, ax
mov ax, #0x0300
out dx, ax
mov dx, # VGAREG_GRDC_ADDRESS
mov ax, #0x0204
out dx, ax
mov ax, #0x0005
out dx, ax
mov ax, #0x0406
out dx, ax
ASM_END
}
static void release_font_access()
{
ASM_START
mov dx, # VGAREG_SEQU_ADDRESS
mov ax, #0x0100
out dx, ax
mov ax, #0x0302
out dx, ax
mov ax, #0x0304
out dx, ax
mov ax, #0x0300
out dx, ax
mov dx, # VGAREG_READ_MISC_OUTPUT
in al, dx
and al, #0x01
shl al, 2
or al, #0x0a
mov ah, al
mov al, #0x06
mov dx, # VGAREG_GRDC_ADDRESS
out dx, ax
mov ax, #0x0004
out dx, ax
mov ax, #0x1005
out dx, ax
ASM_END
}
ASM_START
idiv_u:
xor dx,dx
div bx
ret
ASM_END
static void set_scan_lines(lines) Bit8u lines;
{
Bit16u crtc_addr,cols,page,vde;
Bit8u crtc_r9,ovl,rows;
crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
outb(crtc_addr, 0x09);
crtc_r9 = inb(crtc_addr+1);
crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
outb(crtc_addr+1, crtc_r9);
if(lines==8)
{
biosfn_set_cursor_shape(0x06,0x07);
}
else
{
biosfn_set_cursor_shape(lines-4,lines-3);
}
write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
outb(crtc_addr, 0x12);
vde = inb(crtc_addr+1);
outb(crtc_addr, 0x07);
ovl = inb(crtc_addr+1);
vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
rows = vde / lines;
write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
}
static void biosfn_load_text_user_pat (AL,ES,BP,CX,DX,BL,BH) Bit8u AL;Bit16u ES;Bit16u BP;Bit16u CX;Bit16u DX;Bit8u BL;Bit8u BH;
{
Bit16u blockaddr,dest,i,src;
get_font_access();
blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
for(i=0;i<CX;i++)
{
src = BP + i * BH;
dest = blockaddr + (DX + i) * 32;
memcpyb(0xA000, dest, ES, src, BH);
}
release_font_access();
if(AL>=0x10)
{
set_scan_lines(BH);
}
}
static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL;
{
Bit16u blockaddr,dest,i,src;
get_font_access();
blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
for(i=0;i<0x100;i++)
{
src = i * 14;
dest = blockaddr + i * 32;
memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14);
}
release_font_access();
if(AL>=0x10)
{
set_scan_lines(14);
}
}
static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL;
{
Bit16u blockaddr,dest,i,src;
get_font_access();
blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
for(i=0;i<0x100;i++)
{
src = i * 8;
dest = blockaddr + i * 32;
memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8);
}
release_font_access();
if(AL>=0x10)
{
set_scan_lines(8);
}
}
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_set_text_block_specifier:
push ax
push dx
mov dx, # VGAREG_SEQU_ADDRESS
mov ah, bl
mov al, #0x03
out dx, ax
pop dx
pop ax
ret
ASM_END
// --------------------------------------------------------------------------------------------
static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL;
{
Bit16u blockaddr,dest,i,src;
get_font_access();
blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
for(i=0;i<0x100;i++)
{
src = i * 16;
dest = blockaddr + i * 32;
memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16);
}
release_font_access();
if(AL>=0x10)
{
set_scan_lines(16);
}
}
static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
{
#ifdef DEBUG
unimplemented();
#endif
}
static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL;
{
#ifdef DEBUG
unimplemented();
#endif
}
static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
{
#ifdef DEBUG
unimplemented();
#endif
}
static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
{
#ifdef DEBUG
unimplemented();
#endif
}
static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
{
#ifdef DEBUG
unimplemented();
#endif
}
// --------------------------------------------------------------------------------------------
static void biosfn_get_font_info (BH,ES,BP,CX,DX)
Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX;
{Bit16u ss=get_SS();
switch(BH)
{case 0x00:
write_word(ss,ES,read_word(0x00,0x1f*4));
write_word(ss,BP,read_word(0x00,(0x1f*4)+2));
break;
case 0x01:
write_word(ss,ES,read_word(0x00,0x43*4));
write_word(ss,BP,read_word(0x00,(0x43*4)+2));
break;
case 0x02:
write_word(ss,ES,0xC000);
write_word(ss,BP,vgafont14);
break;
case 0x03:
write_word(ss,ES,0xC000);
write_word(ss,BP,vgafont8);
break;
case 0x04:
write_word(ss,ES,0xC000);
write_word(ss,BP,vgafont8+128*8);
break;
case 0x05:
write_word(ss,ES,0xC000);
write_word(ss,BP,vgafont14alt);
break;
case 0x06:
write_word(ss,ES,0xC000);
write_word(ss,BP,vgafont16);
break;
case 0x07:
write_word(ss,ES,0xC000);
write_word(ss,BP,vgafont16alt);
break;
default:
#ifdef DEBUG
printf("Get font info BH(%02x) was discarded\n",BH);
#endif
return;
}
// Set byte/char of on screen font
write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT));
// Set Highest char row
write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS));
}
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_get_ega_info:
push ds
push ax
mov ax, # BIOSMEM_SEG
mov ds, ax
xor ch, ch
mov bx, # BIOSMEM_SWITCHES
mov cl, [bx]
and cl, #0x0f
mov bx, # BIOSMEM_CRTC_ADDRESS
mov ax, [bx]
mov bx, #0x0003
cmp ax, # VGAREG_MDA_CRTC_ADDRESS
jne mode_ega_color
mov bh, #0x01
mode_ega_color:
pop ax
pop ds
ret
ASM_END
// --------------------------------------------------------------------------------------------
static void biosfn_alternate_prtsc()
{
#ifdef DEBUG
unimplemented();
#endif
}
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_select_vert_res:
; res : 00 200 lines, 01 350 lines, 02 400 lines
push ds
push bx
push dx
mov dl, al
mov ax, # BIOSMEM_SEG
mov ds, ax
mov bx, # BIOSMEM_MODESET_CTL
mov al, [bx]
mov bx, # BIOSMEM_SWITCHES
mov ah, [bx]
cmp dl, #0x01
je vert_res_350
jb vert_res_200
cmp dl, #0x02
je vert_res_400
#ifdef DEBUG
mov al, dl
xor ah, ah
push ax
mov bx, #msg_vert_res
push bx
call _printf
add sp, #4
#endif
jmp set_retcode
vert_res_400:
; reset modeset ctl bit 7 and set bit 4
; set switches bit 3-0 to 0x09
and al, #0x7f
or al, #0x10
and ah, #0xf0
or ah, #0x09
jnz set_vert_res
vert_res_350:
; reset modeset ctl bit 7 and bit 4
; set switches bit 3-0 to 0x09
and al, #0x6f
and ah, #0xf0
or ah, #0x09
jnz set_vert_res
vert_res_200:
; set modeset ctl bit 7 and reset bit 4
; set switches bit 3-0 to 0x08
and al, #0xef
or al, #0x80
and ah, #0xf0
or ah, #0x08
set_vert_res:
mov bx, # BIOSMEM_MODESET_CTL
mov [bx], al
mov bx, # BIOSMEM_SWITCHES
mov [bx], ah
set_retcode:
mov ax, #0x1212
pop dx
pop bx
pop ds
ret
#ifdef DEBUG
msg_vert_res:
.ascii "Select vert res (%02x) was discarded"
.byte 0x0d,0x0a,0x00
#endif
biosfn_enable_default_palette_loading:
push ds
push bx
push dx
mov dl, al
and dl, #0x01
shl dl, 3
mov ax, # BIOSMEM_SEG
mov ds, ax
mov bx, # BIOSMEM_MODESET_CTL
mov al, [bx]
and al, #0xf7
or al, dl
mov [bx], al
mov ax, #0x1212
pop dx
pop bx
pop ds
ret
biosfn_enable_video_addressing:
push bx
push dx
mov bl, al
and bl, #0x01
xor bl, #0x01
shl bl, 1
mov dx, # VGAREG_READ_MISC_OUTPUT
in al, dx
and al, #0xfd
or al, bl
mov dx, # VGAREG_WRITE_MISC_OUTPUT
out dx, al
mov ax, #0x1212
pop dx
pop bx
ret
biosfn_enable_grayscale_summing:
push ds
push bx
push dx
mov dl, al
and dl, #0x01
xor dl, #0x01
shl dl, 1
mov ax, # BIOSMEM_SEG
mov ds, ax
mov bx, # BIOSMEM_MODESET_CTL
mov al, [bx]
and al, #0xfd
or al, dl
mov [bx], al
mov ax, #0x1212
pop dx
pop bx
pop ds
ret
biosfn_enable_cursor_emulation:
push ds
push bx
push dx
mov dl, al
and dl, #0x01
xor dl, #0x01
mov ax, # BIOSMEM_SEG
mov ds, ax
mov bx, # BIOSMEM_MODESET_CTL
mov al, [bx]
and al, #0xfe
or al, dl
mov [bx], al
mov ax, #0x1212
pop dx
pop bx
pop ds
ret
ASM_END
// --------------------------------------------------------------------------------------------
static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
{
#ifdef DEBUG
unimplemented();
#endif
}
static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
{
#ifdef DEBUG
unimplemented();
#endif
}
// --------------------------------------------------------------------------------------------
static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset)
Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset;
{
Bit16u newcurs,oldcurs,dummy;
Bit8u car,carattr;
// Read curs info for the page
biosfn_get_cursor_pos(page,&dummy,&oldcurs);
// if row=0xff special case : use current cursor position
if(row==0xff)
{col=oldcurs&0x00ff;
row=(oldcurs&0xff00)>>8;
}
newcurs=row; newcurs<<=8; newcurs+=col;
biosfn_set_cursor_pos(page,newcurs);
while(count--!=0)
{
car=read_byte(seg,offset++);
if((flag&0x02)!=0)
attr=read_byte(seg,offset++);
biosfn_write_teletype(car,page,attr,WITH_ATTR);
}
// Set back curs pos
if((flag&0x01)==0)
biosfn_set_cursor_pos(page,oldcurs);
}
// --------------------------------------------------------------------------------------------
ASM_START
biosfn_group_1A:
cmp al, #0x00
je biosfn_read_display_code
cmp al, #0x01
je biosfn_set_display_code
#ifdef DEBUG
call _unknown
#endif
ret
biosfn_read_display_code:
push ds
push ax
mov ax, # BIOSMEM_SEG
mov ds, ax
mov bx, # BIOSMEM_DCC_INDEX
mov al, [bx]
mov bl, al
xor bh, bh
pop ax
mov al, ah
pop ds
ret
biosfn_set_display_code:
push ds
push ax
push bx
mov ax, # BIOSMEM_SEG
mov ds, ax
mov ax, bx
mov bx, # BIOSMEM_DCC_INDEX
mov [bx], al
#ifdef DEBUG
mov al, ah
xor ah, ah
push ax
mov bx, #msg_alt_dcc
push bx
call _printf
add sp, #4
#endif
pop bx
pop ax
mov al, ah
pop ds
ret
#ifdef DEBUG
msg_alt_dcc:
.ascii "Alternate Display code (%02x) was discarded"
.byte 0x0d,0x0a,0x00
#endif
ASM_END
// --------------------------------------------------------------------------------------------
static void biosfn_read_state_info (BX,ES,DI)
Bit16u BX;Bit16u ES;Bit16u DI;
{
// Address of static functionality table
write_word(ES,DI+0x00,&static_functionality);
write_word(ES,DI+0x02,0xC000);
// Hard coded copy from BIOS area. Should it be cleaner ?
memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
write_byte(ES,DI+0x26,0);
write_byte(ES,DI+0x27,16);
write_byte(ES,DI+0x28,0);
write_byte(ES,DI+0x29,8);
write_byte(ES,DI+0x2a,2);
write_byte(ES,DI+0x2b,0);
write_byte(ES,DI+0x2c,0);
write_byte(ES,DI+0x31,3);
write_byte(ES,DI+0x32,0);
memsetb(ES,DI+0x33,0,13);
}
// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
static Bit16u biosfn_read_video_state_size2 (CX)
Bit16u CX;
{
Bit16u size;
size = 0;
if (CX & 1) {
size += 0x46;
}
if (CX & 2) {
size += (5 + 8 + 5) * 2 + 6;
}
if (CX & 4) {
size += 3 + 256 * 3 + 1;
}
return size;
}
static void biosfn_read_video_state_size (CX, BX)
Bit16u CX; Bit16u *BX;
{
Bit16u ss=get_SS();
write_word(ss, BX, biosfn_read_video_state_size2(CX));
}
static Bit16u biosfn_save_video_state (CX,ES,BX)
Bit16u CX;Bit16u ES;Bit16u BX;
{
Bit16u i, v, crtc_addr, ar_index;
crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
if (CX & 1) {
write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
write_byte(ES, BX, inb(crtc_addr)); BX++;
write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
inb(VGAREG_ACTL_RESET);
ar_index = inb(VGAREG_ACTL_ADDRESS);
write_byte(ES, BX, ar_index); BX++;
write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
for(i=1;i<=4;i++){
outb(VGAREG_SEQU_ADDRESS, i);
write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
}
outb(VGAREG_SEQU_ADDRESS, 0);
write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
for(i=0;i<=0x18;i++) {
outb(crtc_addr,i);
write_byte(ES, BX, inb(crtc_addr+1)); BX++;
}
for(i=0;i<=0x13;i++) {
inb(VGAREG_ACTL_RESET);
outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
}
inb(VGAREG_ACTL_RESET);
for(i=0;i<=8;i++) {
outb(VGAREG_GRDC_ADDRESS,i);
write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
}
write_word(ES, BX, crtc_addr); BX+= 2;
/* XXX: read plane latches */
write_byte(ES, BX, 0); BX++;
write_byte(ES, BX, 0); BX++;
write_byte(ES, BX, 0); BX++;
write_byte(ES, BX, 0); BX++;
}
if (CX & 2) {
write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
for(i=0;i<8;i++) {
write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
BX += 2;
}
write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
/* current font */
write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
}
if (CX & 4) {
/* XXX: check this */
write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
// Set the whole dac always, from 0
outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
for(i=0;i<256*3;i++) {
write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
}
write_byte(ES, BX, 0); BX++; /* color select register */
}
return BX;
}
static Bit16u biosfn_restore_video_state (CX,ES,BX)
Bit16u CX;Bit16u ES;Bit16u BX;
{
Bit16u i, crtc_addr, v, addr1, ar_index;
if (CX & 1) {
// Reset Attribute Ctl flip-flop
inb(VGAREG_ACTL_RESET);
crtc_addr = read_word(ES, BX + 0x40);
addr1 = BX;
BX += 5;
for(i=1;i<=4;i++){
outb(VGAREG_SEQU_ADDRESS, i);
outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
}
outb(VGAREG_SEQU_ADDRESS, 0);
outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
// Disable CRTC write protection
outw(crtc_addr,0x0011);
// Set CRTC regs
for(i=0;i<=0x18;i++) {
if (i != 0x11) {
outb(crtc_addr,i);
outb(crtc_addr+1, read_byte(ES, BX));
}
BX++;
}
// select crtc base address
v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
if (crtc_addr = 0x3d4)
v |= 0x01;
outb(VGAREG_WRITE_MISC_OUTPUT, v);
// enable write protection if needed
outb(crtc_addr, 0x11);
outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
// Set Attribute Ctl
ar_index = read_byte(ES, addr1 + 0x03);
inb(VGAREG_ACTL_RESET);
for(i=0;i<=0x13;i++) {
outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
}
outb(VGAREG_ACTL_ADDRESS, ar_index);
inb(VGAREG_ACTL_RESET);
for(i=0;i<=8;i++) {
outb(VGAREG_GRDC_ADDRESS,i);
outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
}
BX += 2; /* crtc_addr */
BX += 4; /* plane latches */
outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
outb(crtc_addr, read_byte(ES, addr1)); addr1++;
outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
addr1++;
outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
}
if (CX & 2) {
write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
for(i=0;i<8;i++) {
write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
BX += 2;
}
write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
/* current font */
write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
}
if (CX & 4) {
BX++;
v = read_byte(ES, BX); BX++;
outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
// Set the whole dac always, from 0
outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
for(i=0;i<256*3;i++) {
outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
}
BX++;
outb(VGAREG_DAC_WRITE_ADDRESS, v);
}
return BX;
}
// ============================================================================================
//
// Video Utils
//
// ============================================================================================
// --------------------------------------------------------------------------------------------
static Bit8u find_vga_entry(mode)
Bit8u mode;
{
Bit8u i,line=0xFF;
for(i=0;i<=MODE_MAX;i++)
if(vga_modes[i].svgamode==mode)
{line=i;
break;
}
return line;
}
/* =========================================================== */
/*
* Misc Utils
*/
/* =========================================================== */
// --------------------------------------------------------------------------------------------
static void memsetb(seg,offset,value,count)
Bit16u seg;
Bit16u offset;
Bit16u value;
Bit16u count;
{
ASM_START
push bp
mov bp, sp
push ax
push cx
push es
push di
mov cx, 10[bp] ; count
cmp cx, #0x00
je memsetb_end
mov ax, 4[bp] ; segment
mov es, ax
mov ax, 6[bp] ; offset
mov di, ax
mov al, 8[bp] ; value
cld
rep
stosb
memsetb_end:
pop di
pop es
pop cx
pop ax
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
static void memsetw(seg,offset,value,count)
Bit16u seg;
Bit16u offset;
Bit16u value;
Bit16u count;
{
ASM_START
push bp
mov bp, sp
push ax
push cx
push es
push di
mov cx, 10[bp] ; count
cmp cx, #0x00
je memsetw_end
mov ax, 4[bp] ; segment
mov es, ax
mov ax, 6[bp] ; offset
mov di, ax
mov ax, 8[bp] ; value
cld
rep
stosw
memsetw_end:
pop di
pop es
pop cx
pop ax
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
static void memcpyb(dseg,doffset,sseg,soffset,count)
Bit16u dseg;
Bit16u doffset;
Bit16u sseg;
Bit16u soffset;
Bit16u count;
{
ASM_START
push bp
mov bp, sp
push ax
push cx
push es
push di
push ds
push si
mov cx, 12[bp] ; count
cmp cx, #0x0000
je memcpyb_end
mov ax, 4[bp] ; dsegment
mov es, ax
mov ax, 6[bp] ; doffset
mov di, ax
mov ax, 8[bp] ; ssegment
mov ds, ax
mov ax, 10[bp] ; soffset
mov si, ax
cld
rep
movsb
memcpyb_end:
pop si
pop ds
pop di
pop es
pop cx
pop ax
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
static void memcpyw(dseg,doffset,sseg,soffset,count)
Bit16u dseg;
Bit16u doffset;
Bit16u sseg;
Bit16u soffset;
Bit16u count;
{
ASM_START
push bp
mov bp, sp
push ax
push cx
push es
push di
push ds
push si
mov cx, 12[bp] ; count
cmp cx, #0x0000
je memcpyw_end
mov ax, 4[bp] ; dsegment
mov es, ax
mov ax, 6[bp] ; doffset
mov di, ax
mov ax, 8[bp] ; ssegment
mov ds, ax
mov ax, 10[bp] ; soffset
mov si, ax
cld
rep
movsw
memcpyw_end:
pop si
pop ds
pop di
pop es
pop cx
pop ax
pop bp
ASM_END
}
/* =========================================================== */
/*
* These functions where ripped from Kevin's rombios.c
*/
/* =========================================================== */
// --------------------------------------------------------------------------------------------
static Bit8u
read_byte(seg, offset)
Bit16u seg;
Bit16u offset;
{
ASM_START
push bp
mov bp, sp
push bx
push ds
mov ax, 4[bp] ; segment
mov ds, ax
mov bx, 6[bp] ; offset
mov al, [bx]
;; al = return value (byte)
pop ds
pop bx
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
static Bit16u
read_word(seg, offset)
Bit16u seg;
Bit16u offset;
{
ASM_START
push bp
mov bp, sp
push bx
push ds
mov ax, 4[bp] ; segment
mov ds, ax
mov bx, 6[bp] ; offset
mov ax, [bx]
;; ax = return value (word)
pop ds
pop bx
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
static void
write_byte(seg, offset, data)
Bit16u seg;
Bit16u offset;
Bit8u data;
{
ASM_START
push bp
mov bp, sp
push ax
push bx
push ds
mov ax, 4[bp] ; segment
mov ds, ax
mov bx, 6[bp] ; offset
mov al, 8[bp] ; data byte
mov [bx], al ; write data byte
pop ds
pop bx
pop ax
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
static void
write_word(seg, offset, data)
Bit16u seg;
Bit16u offset;
Bit16u data;
{
ASM_START
push bp
mov bp, sp
push ax
push bx
push ds
mov ax, 4[bp] ; segment
mov ds, ax
mov bx, 6[bp] ; offset
mov ax, 8[bp] ; data word
mov [bx], ax ; write data word
pop ds
pop bx
pop ax
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
Bit8u
inb(port)
Bit16u port;
{
ASM_START
push bp
mov bp, sp
push dx
mov dx, 4[bp]
in al, dx
pop dx
pop bp
ASM_END
}
Bit16u
inw(port)
Bit16u port;
{
ASM_START
push bp
mov bp, sp
push dx
mov dx, 4[bp]
in ax, dx
pop dx
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
void
outb(port, val)
Bit16u port;
Bit8u val;
{
ASM_START
push bp
mov bp, sp
push ax
push dx
mov dx, 4[bp]
mov al, 6[bp]
out dx, al
pop dx
pop ax
pop bp
ASM_END
}
// --------------------------------------------------------------------------------------------
void
outw(port, val)
Bit16u port;
Bit16u val;
{
ASM_START
push bp
mov bp, sp
push ax
push dx
mov dx, 4[bp]
mov ax, 6[bp]
out dx, ax
pop dx
pop ax
pop bp
ASM_END
}
Bit16u get_SS()
{
ASM_START
mov ax, ss
ASM_END
}
#ifdef DEBUG
void unimplemented()
{
printf("--> Unimplemented\n");
}
void unknown()
{
printf("--> Unknown int10\n");
}
#endif
// --------------------------------------------------------------------------------------------
#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
void printf(s)
Bit8u *s;
{
Bit8u c, format_char;
Boolean in_format;
unsigned format_width, i;
Bit16u *arg_ptr;
Bit16u arg_seg, arg, digit, nibble, shift_count;
arg_ptr = &s;
arg_seg = get_SS();
in_format = 0;
format_width = 0;
while (c = read_byte(0xc000, s)) {
if ( c == '%' ) {
in_format = 1;
format_width = 0;
}
else if (in_format) {
if ( (c>='0') && (c<='9') ) {
format_width = (format_width * 10) + (c - '0');
}
else if (c == 'x') {
arg_ptr++; // increment to next arg
arg = read_word(arg_seg, arg_ptr);
if (format_width == 0)
format_width = 4;
i = 0;
digit = format_width - 1;
for (i=0; i<format_width; i++) {
nibble = (arg >> (4 * digit)) & 0x000f;
if (nibble <= 9)
outb(0x0500, nibble + '0');
else
outb(0x0500, (nibble - 10) + 'A');
digit--;
}
in_format = 0;
}
//else if (c == 'd') {
// in_format = 0;
// }
}
else {
outb(0x0500, c);
}
s ++;
}
}
#endif
ASM_START
; get LFB address from PCI
; in - ax: PCI device vendor
; out - ax: LFB address (high 16 bit)
;; NOTE - may be called in protected mode
_pci_get_lfb_addr:
push bx
push cx
push dx
push eax
mov bx, ax
xor cx, cx
mov dl, #0x00
call pci_read_reg
cmp ax, #0xffff
jz pci_get_lfb_addr_5
pci_get_lfb_addr_3:
mov dl, #0x00
call pci_read_reg
cmp ax, bx ;; check vendor
jz pci_get_lfb_addr_4
add cx, #0x8
cmp cx, #0x200 ;; search bus #0 and #1
jb pci_get_lfb_addr_3
pci_get_lfb_addr_5:
xor dx, dx ;; no LFB
jmp pci_get_lfb_addr_6
pci_get_lfb_addr_4:
mov dl, #0x10 ;; I/O space #0
call pci_read_reg
test ax, #0xfff1
jnz pci_get_lfb_addr_5
shr eax, #16
mov dx, ax ;; LFB address
pci_get_lfb_addr_6:
pop eax
mov ax, dx
pop dx
pop cx
pop bx
ret
; read PCI register
; in - cx: device/function
; in - dl: register
; out - eax: value
pci_read_reg:
mov eax, #0x00800000
mov ax, cx
shl eax, #8
mov al, dl
mov dx, #0xcf8
out dx, eax
add dl, #4
in eax, dx
ret
ASM_END
#ifdef VBE
#include "vbe.c"
#endif
#ifdef CIRRUS
#include "clext.c"
#endif
// --------------------------------------------------------------------------------------------
ASM_START
;; DATA_SEG_DEFS_HERE
ASM_END
ASM_START
.ascii "vgabios ends here"
.byte 0x00
vgabios_end:
.byte 0xCB
;; BLOCK_STRINGS_BEGIN
ASM_END