Home | History | Annotate | Download | only in vgabios
      1 // ============================================================================================
      2 /*
      3  * vgabios.c
      4  */
      5 // ============================================================================================
      6 //
      7 //  Copyright (C) 2001-2008 the LGPL VGABios developers Team
      8 //
      9 //  This library is free software; you can redistribute it and/or
     10 //  modify it under the terms of the GNU Lesser General Public
     11 //  License as published by the Free Software Foundation; either
     12 //  version 2 of the License, or (at your option) any later version.
     13 //
     14 //  This library is distributed in the hope that it will be useful,
     15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17 //  Lesser General Public License for more details.
     18 //
     19 //  You should have received a copy of the GNU Lesser General Public
     20 //  License along with this library; if not, write to the Free Software
     21 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     22 //
     23 // ============================================================================================
     24 //
     25 //  This VGA Bios is specific to the plex86/bochs Emulated VGA card.
     26 //  You can NOT drive any physical vga card with it.
     27 //
     28 // ============================================================================================
     29 //
     30 //  This file contains code ripped from :
     31 //   - rombios.c of plex86
     32 //
     33 //  This VGA Bios contains fonts from :
     34 //   - fntcol16.zip (c) by Joseph Gil avalable at :
     35 //      ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
     36 //     These fonts are public domain
     37 //
     38 //  This VGA Bios is based on information taken from :
     39 //   - Kevin Lawton's vga card emulation for bochs/plex86
     40 //   - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
     41 //   - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
     42 //   - Michael Abrash's Graphics Programming Black Book
     43 //   - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
     44 //   - DOSEMU 1.0.1 source code for several tables values and formulas
     45 //
     46 // Thanks for patches, comments and ideas to :
     47 //   - techt (at) pikeonline.net
     48 //
     49 // ============================================================================================
     50 
     51 #include "vgabios.h"
     52 
     53 #ifdef VBE
     54 #include "vbe.h"
     55 #endif
     56 
     57 #define USE_BX_INFO
     58 
     59 /* Declares */
     60 static Bit8u          read_byte();
     61 static Bit16u         read_word();
     62 static void           write_byte();
     63 static void           write_word();
     64 static Bit8u          inb();
     65 static Bit16u         inw();
     66 static void           outb();
     67 static void           outw();
     68 
     69 static Bit16u         get_SS();
     70 
     71 // Output
     72 static void           printf();
     73 static void           unimplemented();
     74 static void           unknown();
     75 
     76 static Bit8u find_vga_entry();
     77 
     78 static void memsetb();
     79 static void memsetw();
     80 static void memcpyb();
     81 static void memcpyw();
     82 
     83 static void biosfn_set_video_mode();
     84 static void biosfn_set_cursor_shape();
     85 static void biosfn_set_cursor_pos();
     86 static void biosfn_get_cursor_pos();
     87 static void biosfn_set_active_page();
     88 static void biosfn_scroll();
     89 static void biosfn_read_char_attr();
     90 static void biosfn_write_char_attr();
     91 static void biosfn_write_char_only();
     92 static void biosfn_write_pixel();
     93 static void biosfn_read_pixel();
     94 static void biosfn_write_teletype();
     95 static void biosfn_perform_gray_scale_summing();
     96 static void biosfn_load_text_user_pat();
     97 static void biosfn_load_text_8_14_pat();
     98 static void biosfn_load_text_8_8_pat();
     99 static void biosfn_load_text_8_16_pat();
    100 static void biosfn_load_gfx_8_8_chars();
    101 static void biosfn_load_gfx_user_chars();
    102 static void biosfn_load_gfx_8_14_chars();
    103 static void biosfn_load_gfx_8_8_dd_chars();
    104 static void biosfn_load_gfx_8_16_chars();
    105 static void biosfn_get_font_info();
    106 static void biosfn_alternate_prtsc();
    107 static void biosfn_switch_video_interface();
    108 static void biosfn_enable_video_refresh_control();
    109 static void biosfn_write_string();
    110 static void biosfn_read_state_info();
    111 static void biosfn_read_video_state_size();
    112 static Bit16u biosfn_save_video_state();
    113 static Bit16u biosfn_restore_video_state();
    114 extern Bit8u video_save_pointer_table[];
    115 
    116 // This is for compiling with gcc2 and gcc3
    117 #define ASM_START #asm
    118 #define ASM_END   #endasm
    119 
    120 ASM_START
    121 
    122 MACRO SET_INT_VECTOR
    123   push ds
    124   xor ax, ax
    125   mov ds, ax
    126   mov ax, ?3
    127   mov ?1*4, ax
    128   mov ax, ?2
    129   mov ?1*4+2, ax
    130   pop ds
    131 MEND
    132 
    133 ASM_END
    134 
    135 ASM_START
    136 .text
    137 .rom
    138 .org 0
    139 
    140 use16 386
    141 
    142 vgabios_start:
    143 .byte	0x55, 0xaa	/* BIOS signature, required for BIOS extensions */
    144 
    145 .byte	0x40		/* BIOS extension length in units of 512 bytes */
    146 
    147 
    148 vgabios_entry_point:
    149 
    150   jmp vgabios_init_func
    151 
    152 #ifdef PCIBIOS
    153 .org 0x18
    154 .word vgabios_pci_data
    155 #endif
    156 
    157 // Info from Bart Oldeman
    158 .org 0x1e
    159 .ascii  "IBM"
    160 .byte   0x00
    161 
    162 vgabios_name:
    163 .ascii	"Plex86/Bochs VGABios"
    164 #ifdef PCIBIOS
    165 .ascii	" (PCI)"
    166 #endif
    167 .ascii	" "
    168 .byte	0x00
    169 
    170 vgabios_version:
    171 #ifndef VGABIOS_VERS
    172 .ascii	"current-cvs"
    173 #else
    174 .ascii VGABIOS_VERS
    175 #endif
    176 .ascii	" "
    177 
    178 vgabios_date:
    179 .ascii  VGABIOS_DATE
    180 .byte   0x0a,0x0d
    181 .byte	0x00
    182 
    183 vgabios_copyright:
    184 .ascii	"(C) 2008 the LGPL VGABios developers Team"
    185 .byte	0x0a,0x0d
    186 .byte	0x00
    187 
    188 vgabios_license:
    189 .ascii	"This VGA/VBE Bios is released under the GNU LGPL"
    190 .byte	0x0a,0x0d
    191 .byte	0x0a,0x0d
    192 .byte	0x00
    193 
    194 vgabios_website:
    195 .ascii	"Please visit :"
    196 .byte	0x0a,0x0d
    197 ;;.ascii  " . http://www.plex86.org"
    198 ;;.byte	0x0a,0x0d
    199 .ascii	" . http://bochs.sourceforge.net"
    200 .byte	0x0a,0x0d
    201 .ascii	" . http://www.nongnu.org/vgabios"
    202 .byte	0x0a,0x0d
    203 .byte	0x0a,0x0d
    204 .byte	0x00
    205 
    206 #ifdef PCIBIOS
    207 vgabios_pci_data:
    208 .ascii "PCIR"
    209 #ifdef CIRRUS
    210 .word 0x1013
    211 .word 0x00b8 // CLGD5446
    212 #else
    213 #error "Unknown PCI vendor and device id"
    214 #endif
    215 .word 0 // reserved
    216 .word 0x18 // dlen
    217 .byte 0 // revision
    218 .byte 0x0 // class,hi: vga display
    219 .word 0x300 // class,lo: vga display
    220 .word 0x40 // bios size
    221 .word 1 // revision
    222 .byte 0 // intel x86 data
    223 .byte 0x80 // last image
    224 .word 0 // reserved
    225 #endif
    226 
    227 
    228 ;; ============================================================================================
    229 ;;
    230 ;; Init Entry point
    231 ;;
    232 ;; ============================================================================================
    233 vgabios_init_func:
    234 
    235 ;; init vga card
    236   call init_vga_card
    237 
    238 ;; init basic bios vars
    239   call init_bios_area
    240 
    241 #ifdef VBE
    242 ;; init vbe functions
    243   call vbe_init
    244 #endif
    245 
    246 ;; set int10 vect
    247   SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler)
    248 
    249 #ifdef CIRRUS
    250   call cirrus_init
    251 #endif
    252 
    253 ;; display splash screen
    254   call _display_splash_screen
    255 
    256 ;; init video mode and clear the screen
    257   mov ax,#0x0003
    258   int #0x10
    259 
    260 ;; show info
    261   call _display_info
    262 
    263 #ifdef VBE
    264 ;; show vbe info
    265   call vbe_display_info
    266 #endif
    267 
    268 #ifdef CIRRUS
    269 ;; show cirrus info
    270   call cirrus_display_info
    271 #endif
    272 
    273   retf
    274 ASM_END
    275 
    276 /*
    277  *  int10 handled here
    278  */
    279 ASM_START
    280 vgabios_int10_handler:
    281   pushf
    282 #ifdef DEBUG
    283   push es
    284   push ds
    285   pusha
    286   mov   bx, #0xc000
    287   mov   ds, bx
    288   call _int10_debugmsg
    289   popa
    290   pop ds
    291   pop es
    292 #endif
    293   cmp   ah, #0x0f
    294   jne   int10_test_1A
    295   call  biosfn_get_video_mode
    296   jmp   int10_end
    297 int10_test_1A:
    298   cmp   ah, #0x1a
    299   jne   int10_test_0B
    300   call  biosfn_group_1A
    301   jmp   int10_end
    302 int10_test_0B:
    303   cmp   ah, #0x0b
    304   jne   int10_test_1103
    305   call  biosfn_group_0B
    306   jmp   int10_end
    307 int10_test_1103:
    308   cmp   ax, #0x1103
    309   jne   int10_test_12
    310   call  biosfn_set_text_block_specifier
    311   jmp   int10_end
    312 int10_test_12:
    313   cmp   ah, #0x12
    314   jne   int10_test_101B
    315   cmp   bl, #0x10
    316   jne   int10_test_BL30
    317   call  biosfn_get_ega_info
    318   jmp   int10_end
    319 int10_test_BL30:
    320   cmp   bl, #0x30
    321   jne   int10_test_BL31
    322   call  biosfn_select_vert_res
    323   jmp   int10_end
    324 int10_test_BL31:
    325   cmp   bl, #0x31
    326   jne   int10_test_BL32
    327   call  biosfn_enable_default_palette_loading
    328   jmp   int10_end
    329 int10_test_BL32:
    330   cmp   bl, #0x32
    331   jne   int10_test_BL33
    332   call  biosfn_enable_video_addressing
    333   jmp   int10_end
    334 int10_test_BL33:
    335   cmp   bl, #0x33
    336   jne   int10_test_BL34
    337   call  biosfn_enable_grayscale_summing
    338   jmp   int10_end
    339 int10_test_BL34:
    340   cmp   bl, #0x34
    341   jne   int10_normal
    342   call  biosfn_enable_cursor_emulation
    343   jmp   int10_end
    344 int10_test_101B:
    345   cmp   ax, #0x101b
    346   je    int10_normal
    347   cmp   ah, #0x10
    348 #ifndef VBE
    349   jne   int10_normal
    350 #else
    351   jne   int10_test_4F
    352 #endif
    353   call  biosfn_group_10
    354   jmp   int10_end
    355 #ifdef VBE
    356 int10_test_4F:
    357   cmp   ah, #0x4f
    358   jne   int10_normal
    359   cmp   al, #0x03
    360   jne   int10_test_vbe_05
    361   call  vbe_biosfn_return_current_mode
    362   jmp   int10_end
    363 int10_test_vbe_05:
    364   cmp   al, #0x05
    365   jne   int10_test_vbe_06
    366   call  vbe_biosfn_display_window_control
    367   jmp   int10_end
    368 int10_test_vbe_06:
    369   cmp   al, #0x06
    370   jne   int10_test_vbe_07
    371   call  vbe_biosfn_set_get_logical_scan_line_length
    372   jmp   int10_end
    373 int10_test_vbe_07:
    374   cmp   al, #0x07
    375   jne   int10_test_vbe_08
    376   call  vbe_biosfn_set_get_display_start
    377   jmp   int10_end
    378 int10_test_vbe_08:
    379   cmp   al, #0x08
    380   jne   int10_test_vbe_0A
    381   call  vbe_biosfn_set_get_dac_palette_format
    382   jmp   int10_end
    383 int10_test_vbe_0A:
    384   cmp   al, #0x0A
    385   jne   int10_normal
    386   call  vbe_biosfn_return_protected_mode_interface
    387   jmp   int10_end
    388 #endif
    389 
    390 int10_normal:
    391   push es
    392   push ds
    393   pusha
    394 
    395 ;; We have to set ds to access the right data segment
    396   mov   bx, #0xc000
    397   mov   ds, bx
    398   call _int10_func
    399 
    400   popa
    401   pop ds
    402   pop es
    403 int10_end:
    404   popf
    405   iret
    406 ASM_END
    407 
    408 #include "vgatables.h"
    409 #include "vgafonts.h"
    410 
    411 /*
    412  * Boot time harware inits
    413  */
    414 ASM_START
    415 init_vga_card:
    416 ;; switch to color mode and enable CPU access 480 lines
    417   mov dx, #0x3C2
    418   mov al, #0xC3
    419   outb dx,al
    420 
    421 ;; more than 64k 3C4/04
    422   mov dx, #0x3C4
    423   mov al, #0x04
    424   outb dx,al
    425   mov dx, #0x3C5
    426   mov al, #0x02
    427   outb dx,al
    428 
    429 #if defined(USE_BX_INFO) || defined(DEBUG)
    430   mov  bx, #msg_vga_init
    431   push bx
    432   call _printf
    433   inc  sp
    434   inc  sp
    435 #endif
    436   ret
    437 
    438 #if defined(USE_BX_INFO) || defined(DEBUG)
    439 msg_vga_init:
    440 .ascii "VGABios $Id$"
    441 .byte 0x0d,0x0a,0x00
    442 #endif
    443 ASM_END
    444 
    445 // --------------------------------------------------------------------------------------------
    446 /*
    447  *  Boot time bios area inits
    448  */
    449 ASM_START
    450 init_bios_area:
    451   push  ds
    452   mov   ax, # BIOSMEM_SEG
    453   mov   ds, ax
    454 
    455 ;; init detected hardware BIOS Area
    456   mov   bx, # BIOSMEM_INITIAL_MODE
    457   mov   ax, [bx]
    458   and   ax, #0xffcf
    459 ;; set 80x25 color (not clear from RBIL but usual)
    460   or    ax, #0x0020
    461   mov   [bx], ax
    462 
    463 ;; Just for the first int10 find its children
    464 
    465 ;; the default char height
    466   mov   bx, # BIOSMEM_CHAR_HEIGHT
    467   mov   al, #0x10
    468   mov   [bx], al
    469 
    470 ;; Clear the screen
    471   mov   bx, # BIOSMEM_VIDEO_CTL
    472   mov   al, #0x60
    473   mov   [bx], al
    474 
    475 ;; Set the basic screen we have
    476   mov   bx, # BIOSMEM_SWITCHES
    477   mov   al, #0xf9
    478   mov   [bx], al
    479 
    480 ;; Set the basic modeset options
    481   mov   bx, # BIOSMEM_MODESET_CTL
    482   mov   al, #0x51
    483   mov   [bx], al
    484 
    485 ;; Set the  default MSR
    486   mov   bx, # BIOSMEM_CURRENT_MSR
    487   mov   al, #0x09
    488   mov   [bx], al
    489 
    490   pop ds
    491   ret
    492 
    493 _video_save_pointer_table:
    494   .word _video_param_table
    495   .word 0xc000
    496 
    497   .word 0 /* XXX: fill it */
    498   .word 0
    499 
    500   .word 0 /* XXX: fill it */
    501   .word 0
    502 
    503   .word 0 /* XXX: fill it */
    504   .word 0
    505 
    506   .word 0 /* XXX: fill it */
    507   .word 0
    508 
    509   .word 0 /* XXX: fill it */
    510   .word 0
    511 
    512   .word 0 /* XXX: fill it */
    513   .word 0
    514 
    515 ASM_END
    516 
    517 // --------------------------------------------------------------------------------------------
    518 /*
    519  *  Boot time Splash screen
    520  */
    521 static void display_splash_screen()
    522 {
    523 }
    524 
    525 // --------------------------------------------------------------------------------------------
    526 /*
    527  *  Tell who we are
    528  */
    529 
    530 static void display_info()
    531 {
    532 ASM_START
    533  mov ax,#0xc000
    534  mov ds,ax
    535  mov si,#vgabios_name
    536  call _display_string
    537  mov si,#vgabios_version
    538  call _display_string
    539 
    540  ;;mov si,#vgabios_copyright
    541  ;;call _display_string
    542  ;;mov si,#crlf
    543  ;;call _display_string
    544 
    545  mov si,#vgabios_license
    546  call _display_string
    547  mov si,#vgabios_website
    548  call _display_string
    549 ASM_END
    550 }
    551 
    552 static void display_string()
    553 {
    554  // Get length of string
    555 ASM_START
    556  mov ax,ds
    557  mov es,ax
    558  mov di,si
    559  xor cx,cx
    560  not cx
    561  xor al,al
    562  cld
    563  repne
    564   scasb
    565  not cx
    566  dec cx
    567  push cx
    568 
    569  mov ax,#0x0300
    570  mov bx,#0x0000
    571  int #0x10
    572 
    573  pop cx
    574  mov ax,#0x1301
    575  mov bx,#0x000b
    576  mov bp,si
    577  int #0x10
    578 ASM_END
    579 }
    580 
    581 // --------------------------------------------------------------------------------------------
    582 #ifdef DEBUG
    583 static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
    584   Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
    585 {
    586  // 0E is write char...
    587  if(GET_AH()!=0x0E)
    588   printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
    589 }
    590 #endif
    591 
    592 // --------------------------------------------------------------------------------------------
    593 /*
    594  * int10 main dispatcher
    595  */
    596 static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
    597   Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
    598 {
    599 
    600  // BIOS functions
    601  switch(GET_AH())
    602   {
    603    case 0x00:
    604      biosfn_set_video_mode(GET_AL());
    605      switch(GET_AL()&0x7F)
    606       {case 6:
    607         SET_AL(0x3F);
    608         break;
    609        case 0:
    610        case 1:
    611        case 2:
    612        case 3:
    613        case 4:
    614        case 5:
    615        case 7:
    616         SET_AL(0x30);
    617         break;
    618       default:
    619         SET_AL(0x20);
    620       }
    621      break;
    622    case 0x01:
    623      biosfn_set_cursor_shape(GET_CH(),GET_CL());
    624      break;
    625    case 0x02:
    626      biosfn_set_cursor_pos(GET_BH(),DX);
    627      break;
    628    case 0x03:
    629      biosfn_get_cursor_pos(GET_BH(),&CX,&DX);
    630      break;
    631    case 0x04:
    632      // Read light pen pos (unimplemented)
    633 #ifdef DEBUG
    634      unimplemented();
    635 #endif
    636      AX=0x00;
    637      BX=0x00;
    638      CX=0x00;
    639      DX=0x00;
    640      break;
    641    case 0x05:
    642      biosfn_set_active_page(GET_AL());
    643      break;
    644    case 0x06:
    645      biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
    646      break;
    647    case 0x07:
    648      biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
    649      break;
    650    case 0x08:
    651      biosfn_read_char_attr(GET_BH(),&AX);
    652      break;
    653    case 0x09:
    654      biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
    655      break;
    656    case 0x0A:
    657      biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
    658      break;
    659    case 0x0C:
    660      biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
    661      break;
    662    case 0x0D:
    663      biosfn_read_pixel(GET_BH(),CX,DX,&AX);
    664      break;
    665    case 0x0E:
    666      // Ralf Brown Interrupt list is WRONG on bh(page)
    667      // We do output only on the current page !
    668      biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
    669      break;
    670    case 0x10:
    671      // All other functions of group AH=0x10 rewritten in assembler
    672      biosfn_perform_gray_scale_summing(BX,CX);
    673      break;
    674    case 0x11:
    675      switch(GET_AL())
    676       {
    677        case 0x00:
    678        case 0x10:
    679         biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
    680         break;
    681        case 0x01:
    682        case 0x11:
    683         biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
    684         break;
    685        case 0x02:
    686        case 0x12:
    687         biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
    688         break;
    689        case 0x04:
    690        case 0x14:
    691         biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
    692         break;
    693        case 0x20:
    694         biosfn_load_gfx_8_8_chars(ES,BP);
    695         break;
    696        case 0x21:
    697         biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
    698         break;
    699        case 0x22:
    700         biosfn_load_gfx_8_14_chars(GET_BL());
    701         break;
    702        case 0x23:
    703         biosfn_load_gfx_8_8_dd_chars(GET_BL());
    704         break;
    705        case 0x24:
    706         biosfn_load_gfx_8_16_chars(GET_BL());
    707         break;
    708        case 0x30:
    709         biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX);
    710         break;
    711 #ifdef DEBUG
    712        default:
    713         unknown();
    714 #endif
    715       }
    716 
    717      break;
    718    case 0x12:
    719      switch(GET_BL())
    720       {
    721        case 0x20:
    722         biosfn_alternate_prtsc();
    723         break;
    724        case 0x35:
    725         biosfn_switch_video_interface(GET_AL(),ES,DX);
    726         SET_AL(0x12);
    727         break;
    728        case 0x36:
    729         biosfn_enable_video_refresh_control(GET_AL());
    730         SET_AL(0x12);
    731         break;
    732 #ifdef DEBUG
    733        default:
    734         unknown();
    735 #endif
    736       }
    737      break;
    738    case 0x13:
    739      biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
    740      break;
    741    case 0x1B:
    742      biosfn_read_state_info(BX,ES,DI);
    743      SET_AL(0x1B);
    744      break;
    745    case 0x1C:
    746      switch(GET_AL())
    747       {
    748        case 0x00:
    749         biosfn_read_video_state_size(CX,&BX);
    750         break;
    751        case 0x01:
    752         biosfn_save_video_state(CX,ES,BX);
    753         break;
    754        case 0x02:
    755         biosfn_restore_video_state(CX,ES,BX);
    756         break;
    757 #ifdef DEBUG
    758        default:
    759         unknown();
    760 #endif
    761       }
    762      SET_AL(0x1C);
    763      break;
    764 
    765 #ifdef VBE
    766    case 0x4f:
    767      if (vbe_has_vbe_display()) {
    768        switch(GET_AL())
    769        {
    770          case 0x00:
    771           vbe_biosfn_return_controller_information(&AX,ES,DI);
    772           break;
    773          case 0x01:
    774           vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
    775           break;
    776          case 0x02:
    777           vbe_biosfn_set_mode(&AX,BX,ES,DI);
    778           break;
    779          case 0x04:
    780           vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
    781           break;
    782          case 0x09:
    783           //FIXME
    784 #ifdef DEBUG
    785           unimplemented();
    786 #endif
    787           // function failed
    788           AX=0x100;
    789           break;
    790          case 0x0A:
    791           //FIXME
    792 #ifdef DEBUG
    793           unimplemented();
    794 #endif
    795           // function failed
    796           AX=0x100;
    797           break;
    798          default:
    799 #ifdef DEBUG
    800           unknown();
    801 #endif
    802           // function failed
    803           AX=0x100;
    804           }
    805         }
    806         else {
    807           // No VBE display
    808           AX=0x0100;
    809           }
    810         break;
    811 #endif
    812 
    813 #ifdef DEBUG
    814    default:
    815      unknown();
    816 #endif
    817   }
    818 }
    819 
    820 // ============================================================================================
    821 //
    822 // BIOS functions
    823 //
    824 // ============================================================================================
    825 
    826 static void biosfn_set_video_mode(mode) Bit8u mode;
    827 {// mode: Bit 7 is 1 if no clear screen
    828 
    829  // Should we clear the screen ?
    830  Bit8u noclearmem=mode&0x80;
    831  Bit8u line,mmask,*palette,vpti;
    832  Bit16u i,twidth,theightm1,cheight;
    833  Bit8u modeset_ctl,video_ctl,vga_switches;
    834  Bit16u crtc_addr;
    835 
    836 #ifdef VBE
    837  if (vbe_has_vbe_display()) {
    838    dispi_set_enable(VBE_DISPI_DISABLED);
    839   }
    840 #endif // def VBE
    841 
    842  // The real mode
    843  mode=mode&0x7f;
    844 
    845  // find the entry in the video modes
    846  line=find_vga_entry(mode);
    847 
    848 #ifdef DEBUG
    849  printf("mode search %02x found line %02x\n",mode,line);
    850 #endif
    851 
    852  if(line==0xFF)
    853   return;
    854 
    855  vpti=line_to_vpti[line];
    856  twidth=video_param_table[vpti].twidth;
    857  theightm1=video_param_table[vpti].theightm1;
    858  cheight=video_param_table[vpti].cheight;
    859 
    860  // Read the bios vga control
    861  video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
    862 
    863  // Read the bios vga switches
    864  vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
    865 
    866  // Read the bios mode set control
    867  modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
    868 
    869  // Then we know the number of lines
    870 // FIXME
    871 
    872  // if palette loading (bit 3 of modeset ctl = 0)
    873  if((modeset_ctl&0x08)==0)
    874   {// Set the PEL mask
    875    outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
    876 
    877    // Set the whole dac always, from 0
    878    outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
    879 
    880    // From which palette
    881    switch(vga_modes[line].dacmodel)
    882     {case 0:
    883       palette=&palette0;
    884       break;
    885      case 1:
    886       palette=&palette1;
    887       break;
    888      case 2:
    889       palette=&palette2;
    890       break;
    891      case 3:
    892       palette=&palette3;
    893       break;
    894     }
    895    // Always 256*3 values
    896    for(i=0;i<0x0100;i++)
    897     {if(i<=dac_regs[vga_modes[line].dacmodel])
    898       {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
    899        outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
    900        outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
    901       }
    902      else
    903       {outb(VGAREG_DAC_DATA,0);
    904        outb(VGAREG_DAC_DATA,0);
    905        outb(VGAREG_DAC_DATA,0);
    906       }
    907     }
    908    if((modeset_ctl&0x02)==0x02)
    909     {
    910      biosfn_perform_gray_scale_summing(0x00, 0x100);
    911     }
    912   }
    913 
    914  // Reset Attribute Ctl flip-flop
    915  inb(VGAREG_ACTL_RESET);
    916 
    917  // Set Attribute Ctl
    918  for(i=0;i<=0x13;i++)
    919   {outb(VGAREG_ACTL_ADDRESS,i);
    920    outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
    921   }
    922  outb(VGAREG_ACTL_ADDRESS,0x14);
    923  outb(VGAREG_ACTL_WRITE_DATA,0x00);
    924 
    925  // Set Sequencer Ctl
    926  outb(VGAREG_SEQU_ADDRESS,0);
    927  outb(VGAREG_SEQU_DATA,0x03);
    928  for(i=1;i<=4;i++)
    929   {outb(VGAREG_SEQU_ADDRESS,i);
    930    outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
    931   }
    932 
    933  // Set Grafx Ctl
    934  for(i=0;i<=8;i++)
    935   {outb(VGAREG_GRDC_ADDRESS,i);
    936    outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
    937   }
    938 
    939  // Set CRTC address VGA or MDA
    940  crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
    941 
    942  // Disable CRTC write protection
    943  outw(crtc_addr,0x0011);
    944  // Set CRTC regs
    945  for(i=0;i<=0x18;i++)
    946   {outb(crtc_addr,i);
    947    outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
    948   }
    949 
    950  // Set the misc register
    951  outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
    952 
    953  // Enable video
    954  outb(VGAREG_ACTL_ADDRESS,0x20);
    955  inb(VGAREG_ACTL_RESET);
    956 
    957  if(noclearmem==0x00)
    958   {
    959    if(vga_modes[line].class==TEXT)
    960     {
    961      memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
    962     }
    963    else
    964     {
    965      if(mode<0x0d)
    966       {
    967        memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
    968       }
    969      else
    970       {
    971        outb( VGAREG_SEQU_ADDRESS, 0x02 );
    972        mmask = inb( VGAREG_SEQU_DATA );
    973        outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
    974        memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
    975        outb( VGAREG_SEQU_DATA, mmask );
    976       }
    977     }
    978   }
    979 
    980  // Set the BIOS mem
    981  write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
    982  write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
    983  write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l);
    984  write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
    985  write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
    986  write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
    987  write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
    988  write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
    989  write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
    990 
    991  // FIXME We nearly have the good tables. to be reworked
    992  write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08);    // 8 is VGA should be ok for now
    993  write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table);
    994  write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000);
    995 
    996  // FIXME
    997  write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
    998  write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
    999 
   1000  // Set cursor shape
   1001  if(vga_modes[line].class==TEXT)
   1002   {
   1003    biosfn_set_cursor_shape(0x06,0x07);
   1004   }
   1005 
   1006  // Set cursor pos for page 0..7
   1007  for(i=0;i<8;i++)
   1008   biosfn_set_cursor_pos(i,0x0000);
   1009 
   1010  // Set active page 0
   1011  biosfn_set_active_page(0x00);
   1012 
   1013  // Write the fonts in memory
   1014  if(vga_modes[line].class==TEXT)
   1015   {
   1016 ASM_START
   1017   ;; copy and activate 8x16 font
   1018   mov ax, #0x1104
   1019   mov bl, #0x00
   1020   int #0x10
   1021   mov ax, #0x1103
   1022   mov bl, #0x00
   1023   int #0x10
   1024 ASM_END
   1025   }
   1026 
   1027  // Set the ints 0x1F and 0x43
   1028 ASM_START
   1029  SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
   1030 ASM_END
   1031 
   1032   switch(cheight)
   1033    {case 8:
   1034 ASM_START
   1035      SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
   1036 ASM_END
   1037      break;
   1038     case 14:
   1039 ASM_START
   1040      SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
   1041 ASM_END
   1042      break;
   1043     case 16:
   1044 ASM_START
   1045      SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
   1046 ASM_END
   1047      break;
   1048    }
   1049 }
   1050 
   1051 // --------------------------------------------------------------------------------------------
   1052 static void biosfn_set_cursor_shape (CH,CL)
   1053 Bit8u CH;Bit8u CL;
   1054 {Bit16u cheight,curs,crtc_addr;
   1055  Bit8u modeset_ctl;
   1056 
   1057  CH&=0x3f;
   1058  CL&=0x1f;
   1059 
   1060  curs=(CH<<8)+CL;
   1061  write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs);
   1062 
   1063  modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
   1064  cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
   1065  if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20))
   1066   {
   1067    if(CL!=(CH+1))
   1068     {
   1069      CH = ((CH+1) * cheight / 8) -1;
   1070     }
   1071    else
   1072     {
   1073      CH = ((CL+1) * cheight / 8) - 2;
   1074     }
   1075    CL = ((CL+1) * cheight / 8) - 1;
   1076   }
   1077 
   1078  // CTRC regs 0x0a and 0x0b
   1079  crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
   1080  outb(crtc_addr,0x0a);
   1081  outb(crtc_addr+1,CH);
   1082  outb(crtc_addr,0x0b);
   1083  outb(crtc_addr+1,CL);
   1084 }
   1085 
   1086 // --------------------------------------------------------------------------------------------
   1087 static void biosfn_set_cursor_pos (page, cursor)
   1088 Bit8u page;Bit16u cursor;
   1089 {
   1090  Bit8u xcurs,ycurs,current;
   1091  Bit16u nbcols,nbrows,address,crtc_addr;
   1092 
   1093  // Should not happen...
   1094  if(page>7)return;
   1095 
   1096  // Bios cursor pos
   1097  write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
   1098 
   1099  // Set the hardware cursor
   1100  current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
   1101  if(page==current)
   1102   {
   1103    // Get the dimensions
   1104    nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1105    nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1106 
   1107    xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
   1108 
   1109    // Calculate the address knowing nbcols nbrows and page num
   1110    address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
   1111 
   1112    // CRTC regs 0x0e and 0x0f
   1113    crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
   1114    outb(crtc_addr,0x0e);
   1115    outb(crtc_addr+1,(address&0xff00)>>8);
   1116    outb(crtc_addr,0x0f);
   1117    outb(crtc_addr+1,address&0x00ff);
   1118   }
   1119 }
   1120 
   1121 // --------------------------------------------------------------------------------------------
   1122 static void biosfn_get_cursor_pos (page,shape, pos)
   1123 Bit8u page;Bit16u *shape;Bit16u *pos;
   1124 {
   1125  Bit16u ss=get_SS();
   1126 
   1127  // Default
   1128  write_word(ss, shape, 0);
   1129  write_word(ss, pos, 0);
   1130 
   1131  if(page>7)return;
   1132  // FIXME should handle VGA 14/16 lines
   1133  write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE));
   1134  write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2));
   1135 }
   1136 
   1137 // --------------------------------------------------------------------------------------------
   1138 static void biosfn_set_active_page (page)
   1139 Bit8u page;
   1140 {
   1141  Bit16u cursor,dummy,crtc_addr;
   1142  Bit16u nbcols,nbrows,address;
   1143  Bit8u mode,line;
   1144 
   1145  if(page>7)return;
   1146 
   1147  // Get the mode
   1148  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1149  line=find_vga_entry(mode);
   1150  if(line==0xFF)return;
   1151 
   1152  // Get pos curs pos for the right page
   1153  biosfn_get_cursor_pos(page,&dummy,&cursor);
   1154 
   1155  if(vga_modes[line].class==TEXT)
   1156   {
   1157    // Get the dimensions
   1158    nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1159    nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1160 
   1161    // Calculate the address knowing nbcols nbrows and page num
   1162    address=SCREEN_MEM_START(nbcols,nbrows,page);
   1163    write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
   1164 
   1165    // Start address
   1166    address=SCREEN_IO_START(nbcols,nbrows,page);
   1167   }
   1168  else
   1169   {
   1170    address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l);
   1171   }
   1172 
   1173  // CRTC regs 0x0c and 0x0d
   1174  crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
   1175  outb(crtc_addr,0x0c);
   1176  outb(crtc_addr+1,(address&0xff00)>>8);
   1177  outb(crtc_addr,0x0d);
   1178  outb(crtc_addr+1,address&0x00ff);
   1179 
   1180  // And change the BIOS page
   1181  write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
   1182 
   1183 #ifdef DEBUG
   1184  printf("Set active page %02x address %04x\n",page,address);
   1185 #endif
   1186 
   1187  // Display the cursor, now the page is active
   1188  biosfn_set_cursor_pos(page,cursor);
   1189 }
   1190 
   1191 // --------------------------------------------------------------------------------------------
   1192 static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
   1193 Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
   1194 {
   1195  Bit16u src,dest;
   1196  Bit8u i;
   1197 
   1198  src=ysrc*cheight*nbcols+xstart;
   1199  dest=ydest*cheight*nbcols+xstart;
   1200  outw(VGAREG_GRDC_ADDRESS, 0x0105);
   1201  for(i=0;i<cheight;i++)
   1202   {
   1203    memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
   1204   }
   1205  outw(VGAREG_GRDC_ADDRESS, 0x0005);
   1206 }
   1207 
   1208 // --------------------------------------------------------------------------------------------
   1209 static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
   1210 Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
   1211 {
   1212  Bit16u dest;
   1213  Bit8u i;
   1214 
   1215  dest=ystart*cheight*nbcols+xstart;
   1216  outw(VGAREG_GRDC_ADDRESS, 0x0205);
   1217  for(i=0;i<cheight;i++)
   1218   {
   1219    memsetb(0xa000,dest+i*nbcols,attr,cols);
   1220   }
   1221  outw(VGAREG_GRDC_ADDRESS, 0x0005);
   1222 }
   1223 
   1224 // --------------------------------------------------------------------------------------------
   1225 static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
   1226 Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
   1227 {
   1228  Bit16u src,dest;
   1229  Bit8u i;
   1230 
   1231  src=((ysrc*cheight*nbcols)>>1)+xstart;
   1232  dest=((ydest*cheight*nbcols)>>1)+xstart;
   1233  for(i=0;i<cheight;i++)
   1234   {
   1235    if (i & 1)
   1236      memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
   1237    else
   1238      memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
   1239   }
   1240 }
   1241 
   1242 // --------------------------------------------------------------------------------------------
   1243 static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
   1244 Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
   1245 {
   1246  Bit16u dest;
   1247  Bit8u i;
   1248 
   1249  dest=((ystart*cheight*nbcols)>>1)+xstart;
   1250  for(i=0;i<cheight;i++)
   1251   {
   1252    if (i & 1)
   1253      memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
   1254    else
   1255      memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
   1256   }
   1257 }
   1258 
   1259 // --------------------------------------------------------------------------------------------
   1260 static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
   1261 Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir;
   1262 {
   1263  // page == 0xFF if current
   1264 
   1265  Bit8u mode,line,cheight,bpp,cols;
   1266  Bit16u nbcols,nbrows,i;
   1267  Bit16u address;
   1268 
   1269  if(rul>rlr)return;
   1270  if(cul>clr)return;
   1271 
   1272  // Get the mode
   1273  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1274  line=find_vga_entry(mode);
   1275  if(line==0xFF)return;
   1276 
   1277  // Get the dimensions
   1278  nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1279  nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1280 
   1281  // Get the current page
   1282  if(page==0xFF)
   1283   page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
   1284 
   1285  if(rlr>=nbrows)rlr=nbrows-1;
   1286  if(clr>=nbcols)clr=nbcols-1;
   1287  if(nblines>nbrows)nblines=0;
   1288  cols=clr-cul+1;
   1289 
   1290  if(vga_modes[line].class==TEXT)
   1291   {
   1292    // Compute the address
   1293    address=SCREEN_MEM_START(nbcols,nbrows,page);
   1294 #ifdef DEBUG
   1295    printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
   1296 #endif
   1297 
   1298    if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
   1299     {
   1300      memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols);
   1301     }
   1302    else
   1303     {// if Scroll up
   1304      if(dir==SCROLL_UP)
   1305       {for(i=rul;i<=rlr;i++)
   1306         {
   1307          if((i+nblines>rlr)||(nblines==0))
   1308           memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
   1309          else
   1310           memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
   1311         }
   1312       }
   1313      else
   1314       {for(i=rlr;i>=rul;i--)
   1315         {
   1316          if((i<rul+nblines)||(nblines==0))
   1317           memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
   1318          else
   1319           memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
   1320          if (i>rlr) break;
   1321         }
   1322       }
   1323     }
   1324   }
   1325  else
   1326   {
   1327    // FIXME gfx mode not complete
   1328    cheight=video_param_table[line_to_vpti[line]].cheight;
   1329    switch(vga_modes[line].memmodel)
   1330     {
   1331      case PLANAR4:
   1332      case PLANAR1:
   1333        if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
   1334         {
   1335          outw(VGAREG_GRDC_ADDRESS, 0x0205);
   1336          memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
   1337          outw(VGAREG_GRDC_ADDRESS, 0x0005);
   1338         }
   1339        else
   1340         {// if Scroll up
   1341          if(dir==SCROLL_UP)
   1342           {for(i=rul;i<=rlr;i++)
   1343             {
   1344              if((i+nblines>rlr)||(nblines==0))
   1345               vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
   1346              else
   1347               vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
   1348             }
   1349           }
   1350          else
   1351           {for(i=rlr;i>=rul;i--)
   1352             {
   1353              if((i<rul+nblines)||(nblines==0))
   1354               vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
   1355              else
   1356               vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
   1357              if (i>rlr) break;
   1358             }
   1359           }
   1360         }
   1361        break;
   1362      case CGA:
   1363        bpp=vga_modes[line].pixbits;
   1364        if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
   1365         {
   1366          memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
   1367         }
   1368        else
   1369         {
   1370          if(bpp==2)
   1371           {
   1372            cul<<=1;
   1373            cols<<=1;
   1374            nbcols<<=1;
   1375           }
   1376          // if Scroll up
   1377          if(dir==SCROLL_UP)
   1378           {for(i=rul;i<=rlr;i++)
   1379             {
   1380              if((i+nblines>rlr)||(nblines==0))
   1381               vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
   1382              else
   1383               vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
   1384             }
   1385           }
   1386          else
   1387           {for(i=rlr;i>=rul;i--)
   1388             {
   1389              if((i<rul+nblines)||(nblines==0))
   1390               vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
   1391              else
   1392               vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
   1393              if (i>rlr) break;
   1394             }
   1395           }
   1396         }
   1397        break;
   1398 #ifdef DEBUG
   1399      default:
   1400        printf("Scroll in graphics mode ");
   1401        unimplemented();
   1402 #endif
   1403     }
   1404   }
   1405 }
   1406 
   1407 // --------------------------------------------------------------------------------------------
   1408 static void biosfn_read_char_attr (page,car)
   1409 Bit8u page;Bit16u *car;
   1410 {Bit16u ss=get_SS();
   1411  Bit8u xcurs,ycurs,mode,line;
   1412  Bit16u nbcols,nbrows,address;
   1413  Bit16u cursor,dummy;
   1414 
   1415  // Get the mode
   1416  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1417  line=find_vga_entry(mode);
   1418  if(line==0xFF)return;
   1419 
   1420  // Get the cursor pos for the page
   1421  biosfn_get_cursor_pos(page,&dummy,&cursor);
   1422  xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
   1423 
   1424  // Get the dimensions
   1425  nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1426  nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1427 
   1428  if(vga_modes[line].class==TEXT)
   1429   {
   1430    // Compute the address
   1431    address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
   1432 
   1433    write_word(ss,car,read_word(vga_modes[line].sstart,address));
   1434   }
   1435  else
   1436   {
   1437    // FIXME gfx mode
   1438 #ifdef DEBUG
   1439    unimplemented();
   1440 #endif
   1441   }
   1442 }
   1443 
   1444 // --------------------------------------------------------------------------------------------
   1445 static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
   1446 Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight;
   1447 {
   1448  Bit8u i,j,mask;
   1449  Bit8u *fdata;
   1450  Bit16u addr,dest,src;
   1451 
   1452  switch(cheight)
   1453   {case 14:
   1454     fdata = &vgafont14;
   1455     break;
   1456    case 16:
   1457     fdata = &vgafont16;
   1458     break;
   1459    default:
   1460     fdata = &vgafont8;
   1461   }
   1462  addr=xcurs+ycurs*cheight*nbcols;
   1463  src = car * cheight;
   1464  outw(VGAREG_SEQU_ADDRESS, 0x0f02);
   1465  outw(VGAREG_GRDC_ADDRESS, 0x0205);
   1466  if(attr&0x80)
   1467   {
   1468    outw(VGAREG_GRDC_ADDRESS, 0x1803);
   1469   }
   1470  else
   1471   {
   1472    outw(VGAREG_GRDC_ADDRESS, 0x0003);
   1473   }
   1474  for(i=0;i<cheight;i++)
   1475   {
   1476    dest=addr+i*nbcols;
   1477    for(j=0;j<8;j++)
   1478     {
   1479      mask=0x80>>j;
   1480      outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
   1481      read_byte(0xa000,dest);
   1482      if(fdata[src+i]&mask)
   1483       {
   1484        write_byte(0xa000,dest,attr&0x0f);
   1485       }
   1486      else
   1487       {
   1488        write_byte(0xa000,dest,0x00);
   1489       }
   1490     }
   1491   }
   1492 ASM_START
   1493   mov dx, # VGAREG_GRDC_ADDRESS
   1494   mov ax, #0xff08
   1495   out dx, ax
   1496   mov ax, #0x0005
   1497   out dx, ax
   1498   mov ax, #0x0003
   1499   out dx, ax
   1500 ASM_END
   1501 }
   1502 
   1503 // --------------------------------------------------------------------------------------------
   1504 static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
   1505 Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp;
   1506 {
   1507  Bit8u i,j,mask,data;
   1508  Bit8u *fdata;
   1509  Bit16u addr,dest,src;
   1510 
   1511  fdata = &vgafont8;
   1512  addr=(xcurs*bpp)+ycurs*320;
   1513  src = car * 8;
   1514  for(i=0;i<8;i++)
   1515   {
   1516    dest=addr+(i>>1)*80;
   1517    if (i & 1) dest += 0x2000;
   1518    mask = 0x80;
   1519    if (bpp == 1)
   1520     {
   1521      if (attr & 0x80)
   1522       {
   1523        data = read_byte(0xb800,dest);
   1524       }
   1525      else
   1526       {
   1527        data = 0x00;
   1528       }
   1529      for(j=0;j<8;j++)
   1530       {
   1531        if (fdata[src+i] & mask)
   1532         {
   1533          if (attr & 0x80)
   1534           {
   1535            data ^= (attr & 0x01) << (7-j);
   1536           }
   1537          else
   1538           {
   1539            data |= (attr & 0x01) << (7-j);
   1540           }
   1541         }
   1542        mask >>= 1;
   1543       }
   1544      write_byte(0xb800,dest,data);
   1545     }
   1546    else
   1547     {
   1548      while (mask > 0)
   1549       {
   1550        if (attr & 0x80)
   1551         {
   1552          data = read_byte(0xb800,dest);
   1553         }
   1554        else
   1555         {
   1556          data = 0x00;
   1557         }
   1558        for(j=0;j<4;j++)
   1559         {
   1560          if (fdata[src+i] & mask)
   1561           {
   1562            if (attr & 0x80)
   1563             {
   1564              data ^= (attr & 0x03) << ((3-j)*2);
   1565             }
   1566            else
   1567             {
   1568              data |= (attr & 0x03) << ((3-j)*2);
   1569             }
   1570           }
   1571          mask >>= 1;
   1572         }
   1573        write_byte(0xb800,dest,data);
   1574        dest += 1;
   1575       }
   1576     }
   1577   }
   1578 }
   1579 
   1580 // --------------------------------------------------------------------------------------------
   1581 static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
   1582 Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;
   1583 {
   1584  Bit8u i,j,mask,data;
   1585  Bit8u *fdata;
   1586  Bit16u addr,dest,src;
   1587 
   1588  fdata = &vgafont8;
   1589  addr=xcurs*8+ycurs*nbcols*64;
   1590  src = car * 8;
   1591  for(i=0;i<8;i++)
   1592   {
   1593    dest=addr+i*nbcols*8;
   1594    mask = 0x80;
   1595    for(j=0;j<8;j++)
   1596     {
   1597      data = 0x00;
   1598      if (fdata[src+i] & mask)
   1599       {
   1600        data = attr;
   1601       }
   1602      write_byte(0xa000,dest+j,data);
   1603      mask >>= 1;
   1604     }
   1605   }
   1606 }
   1607 
   1608 // --------------------------------------------------------------------------------------------
   1609 static void biosfn_write_char_attr (car,page,attr,count)
   1610 Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
   1611 {
   1612  Bit8u cheight,xcurs,ycurs,mode,line,bpp;
   1613  Bit16u nbcols,nbrows,address;
   1614  Bit16u cursor,dummy;
   1615 
   1616  // Get the mode
   1617  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1618  line=find_vga_entry(mode);
   1619  if(line==0xFF)return;
   1620 
   1621  // Get the cursor pos for the page
   1622  biosfn_get_cursor_pos(page,&dummy,&cursor);
   1623  xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
   1624 
   1625  // Get the dimensions
   1626  nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1627  nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1628 
   1629  if(vga_modes[line].class==TEXT)
   1630   {
   1631    // Compute the address
   1632    address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
   1633 
   1634    dummy=((Bit16u)attr<<8)+car;
   1635    memsetw(vga_modes[line].sstart,address,dummy,count);
   1636   }
   1637  else
   1638   {
   1639    // FIXME gfx mode not complete
   1640    cheight=video_param_table[line_to_vpti[line]].cheight;
   1641    bpp=vga_modes[line].pixbits;
   1642    while((count-->0) && (xcurs<nbcols))
   1643     {
   1644      switch(vga_modes[line].memmodel)
   1645       {
   1646        case PLANAR4:
   1647        case PLANAR1:
   1648          write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
   1649          break;
   1650        case CGA:
   1651          write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
   1652          break;
   1653        case LINEAR8:
   1654          write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
   1655          break;
   1656 #ifdef DEBUG
   1657        default:
   1658          unimplemented();
   1659 #endif
   1660       }
   1661      xcurs++;
   1662     }
   1663   }
   1664 }
   1665 
   1666 // --------------------------------------------------------------------------------------------
   1667 static void biosfn_write_char_only (car,page,attr,count)
   1668 Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
   1669 {
   1670  Bit8u cheight,xcurs,ycurs,mode,line,bpp;
   1671  Bit16u nbcols,nbrows,address;
   1672  Bit16u cursor,dummy;
   1673 
   1674  // Get the mode
   1675  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1676  line=find_vga_entry(mode);
   1677  if(line==0xFF)return;
   1678 
   1679  // Get the cursor pos for the page
   1680  biosfn_get_cursor_pos(page,&dummy,&cursor);
   1681  xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
   1682 
   1683  // Get the dimensions
   1684  nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1685  nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1686 
   1687  if(vga_modes[line].class==TEXT)
   1688   {
   1689    // Compute the address
   1690    address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
   1691 
   1692    while(count-->0)
   1693     {write_byte(vga_modes[line].sstart,address,car);
   1694      address+=2;
   1695     }
   1696   }
   1697  else
   1698   {
   1699    // FIXME gfx mode not complete
   1700    cheight=video_param_table[line_to_vpti[line]].cheight;
   1701    bpp=vga_modes[line].pixbits;
   1702    while((count-->0) && (xcurs<nbcols))
   1703     {
   1704      switch(vga_modes[line].memmodel)
   1705       {
   1706        case PLANAR4:
   1707        case PLANAR1:
   1708          write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
   1709          break;
   1710        case CGA:
   1711          write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
   1712          break;
   1713        case LINEAR8:
   1714          write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
   1715          break;
   1716 #ifdef DEBUG
   1717        default:
   1718          unimplemented();
   1719 #endif
   1720       }
   1721      xcurs++;
   1722     }
   1723   }
   1724 }
   1725 
   1726 // --------------------------------------------------------------------------------------------
   1727 ASM_START
   1728 biosfn_group_0B:
   1729   cmp   bh, #0x00
   1730   je    biosfn_set_border_color
   1731   cmp   bh, #0x01
   1732   je    biosfn_set_palette
   1733 #ifdef DEBUG
   1734   call  _unknown
   1735 #endif
   1736   ret
   1737 biosfn_set_border_color:
   1738   push  ax
   1739   push  bx
   1740   push  cx
   1741   push  dx
   1742   mov   dx, # VGAREG_ACTL_RESET
   1743   in    al, dx
   1744   mov   dx, # VGAREG_ACTL_ADDRESS
   1745   mov   al, #0x00
   1746   out   dx, al
   1747   mov   al, bl
   1748   and   al, #0x0f
   1749   test  al, #0x08
   1750   jz    set_low_border
   1751   add   al, #0x08
   1752 set_low_border:
   1753   out   dx, al
   1754   mov   cl, #0x01
   1755   and   bl, #0x10
   1756 set_intensity_loop:
   1757   mov   dx, # VGAREG_ACTL_ADDRESS
   1758   mov   al, cl
   1759   out   dx, al
   1760   mov   dx, # VGAREG_ACTL_READ_DATA
   1761   in    al, dx
   1762   and   al, #0xef
   1763   or    al, bl
   1764   mov   dx, # VGAREG_ACTL_ADDRESS
   1765   out   dx, al
   1766   inc   cl
   1767   cmp   cl, #0x04
   1768   jne   set_intensity_loop
   1769   mov   al, #0x20
   1770   out   dx, al
   1771   pop   dx
   1772   pop   cx
   1773   pop   bx
   1774   pop   ax
   1775   ret
   1776 biosfn_set_palette:
   1777   push  ax
   1778   push  bx
   1779   push  cx
   1780   push  dx
   1781   mov   dx, # VGAREG_ACTL_RESET
   1782   in    al, dx
   1783   mov   cl, #0x01
   1784   and   bl, #0x01
   1785 set_cga_palette_loop:
   1786   mov   dx, # VGAREG_ACTL_ADDRESS
   1787   mov   al, cl
   1788   out   dx, al
   1789   mov   dx, # VGAREG_ACTL_READ_DATA
   1790   in    al, dx
   1791   and   al, #0xfe
   1792   or    al, bl
   1793   mov   dx, # VGAREG_ACTL_ADDRESS
   1794   out   dx, al
   1795   inc   cl
   1796   cmp   cl, #0x04
   1797   jne   set_cga_palette_loop
   1798   mov   al, #0x20
   1799   out   dx, al
   1800   pop   dx
   1801   pop   cx
   1802   pop   bx
   1803   pop   ax
   1804   ret
   1805 ASM_END
   1806 
   1807 // --------------------------------------------------------------------------------------------
   1808 static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
   1809 {
   1810  Bit8u mode,line,mask,attr,data;
   1811  Bit16u addr;
   1812 
   1813  // Get the mode
   1814  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1815  line=find_vga_entry(mode);
   1816  if(line==0xFF)return;
   1817  if(vga_modes[line].class==TEXT)return;
   1818 
   1819  switch(vga_modes[line].memmodel)
   1820   {
   1821    case PLANAR4:
   1822    case PLANAR1:
   1823      addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1824      mask = 0x80 >> (CX & 0x07);
   1825      outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
   1826      outw(VGAREG_GRDC_ADDRESS, 0x0205);
   1827      data = read_byte(0xa000,addr);
   1828      if (AL & 0x80)
   1829       {
   1830        outw(VGAREG_GRDC_ADDRESS, 0x1803);
   1831       }
   1832      write_byte(0xa000,addr,AL);
   1833 ASM_START
   1834      mov dx, # VGAREG_GRDC_ADDRESS
   1835      mov ax, #0xff08
   1836      out dx, ax
   1837      mov ax, #0x0005
   1838      out dx, ax
   1839      mov ax, #0x0003
   1840      out dx, ax
   1841 ASM_END
   1842      break;
   1843    case CGA:
   1844      if(vga_modes[line].pixbits==2)
   1845       {
   1846        addr=(CX>>2)+(DX>>1)*80;
   1847       }
   1848      else
   1849       {
   1850        addr=(CX>>3)+(DX>>1)*80;
   1851       }
   1852      if (DX & 1) addr += 0x2000;
   1853      data = read_byte(0xb800,addr);
   1854      if(vga_modes[line].pixbits==2)
   1855       {
   1856        attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
   1857        mask = 0x03 << ((3 - (CX & 0x03)) * 2);
   1858       }
   1859      else
   1860       {
   1861        attr = (AL & 0x01) << (7 - (CX & 0x07));
   1862        mask = 0x01 << (7 - (CX & 0x07));
   1863       }
   1864      if (AL & 0x80)
   1865       {
   1866        data ^= attr;
   1867       }
   1868      else
   1869       {
   1870        data &= ~mask;
   1871        data |= attr;
   1872       }
   1873      write_byte(0xb800,addr,data);
   1874      break;
   1875    case LINEAR8:
   1876      addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
   1877      write_byte(0xa000,addr,AL);
   1878      break;
   1879 #ifdef DEBUG
   1880    default:
   1881      unimplemented();
   1882 #endif
   1883   }
   1884 }
   1885 
   1886 // --------------------------------------------------------------------------------------------
   1887 static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX;
   1888 {
   1889  Bit8u mode,line,mask,attr,data,i;
   1890  Bit16u addr;
   1891  Bit16u ss=get_SS();
   1892 
   1893  // Get the mode
   1894  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1895  line=find_vga_entry(mode);
   1896  if(line==0xFF)return;
   1897  if(vga_modes[line].class==TEXT)return;
   1898 
   1899  switch(vga_modes[line].memmodel)
   1900   {
   1901    case PLANAR4:
   1902    case PLANAR1:
   1903      addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1904      mask = 0x80 >> (CX & 0x07);
   1905      attr = 0x00;
   1906      for(i=0;i<4;i++)
   1907       {
   1908        outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
   1909        data = read_byte(0xa000,addr) & mask;
   1910        if (data > 0) attr |= (0x01 << i);
   1911       }
   1912      break;
   1913    case CGA:
   1914      addr=(CX>>2)+(DX>>1)*80;
   1915      if (DX & 1) addr += 0x2000;
   1916      data = read_byte(0xb800,addr);
   1917      if(vga_modes[line].pixbits==2)
   1918       {
   1919        attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
   1920       }
   1921      else
   1922       {
   1923        attr = (data >> (7 - (CX & 0x07))) & 0x01;
   1924       }
   1925      break;
   1926    case LINEAR8:
   1927      addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
   1928      attr=read_byte(0xa000,addr);
   1929      break;
   1930    default:
   1931 #ifdef DEBUG
   1932      unimplemented();
   1933 #endif
   1934      attr = 0;
   1935   }
   1936  write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr);
   1937 }
   1938 
   1939 // --------------------------------------------------------------------------------------------
   1940 static void biosfn_write_teletype (car, page, attr, flag)
   1941 Bit8u car;Bit8u page;Bit8u attr;Bit8u flag;
   1942 {// flag = WITH_ATTR / NO_ATTR
   1943 
   1944  Bit8u cheight,xcurs,ycurs,mode,line,bpp;
   1945  Bit16u nbcols,nbrows,address;
   1946  Bit16u cursor,dummy;
   1947 
   1948  // special case if page is 0xff, use current page
   1949  if(page==0xff)
   1950   page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
   1951 
   1952  // Get the mode
   1953  mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
   1954  line=find_vga_entry(mode);
   1955  if(line==0xFF)return;
   1956 
   1957  // Get the cursor pos for the page
   1958  biosfn_get_cursor_pos(page,&dummy,&cursor);
   1959  xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
   1960 
   1961  // Get the dimensions
   1962  nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
   1963  nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   1964 
   1965  switch(car)
   1966   {
   1967    case 7:
   1968     //FIXME should beep
   1969     break;
   1970 
   1971    case 8:
   1972     if(xcurs>0)xcurs--;
   1973     break;
   1974 
   1975    case '\r':
   1976     xcurs=0;
   1977     break;
   1978 
   1979    case '\n':
   1980     ycurs++;
   1981     break;
   1982 
   1983    case '\t':
   1984     do
   1985      {
   1986       biosfn_write_teletype(' ',page,attr,flag);
   1987       biosfn_get_cursor_pos(page,&dummy,&cursor);
   1988       xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
   1989      }while(xcurs%8==0);
   1990     break;
   1991 
   1992    default:
   1993 
   1994     if(vga_modes[line].class==TEXT)
   1995      {
   1996       // Compute the address
   1997       address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
   1998 
   1999       // Write the char
   2000       write_byte(vga_modes[line].sstart,address,car);
   2001 
   2002       if(flag==WITH_ATTR)
   2003        write_byte(vga_modes[line].sstart,address+1,attr);
   2004      }
   2005     else
   2006      {
   2007       // FIXME gfx mode not complete
   2008       cheight=video_param_table[line_to_vpti[line]].cheight;
   2009       bpp=vga_modes[line].pixbits;
   2010       switch(vga_modes[line].memmodel)
   2011        {
   2012         case PLANAR4:
   2013         case PLANAR1:
   2014           write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
   2015           break;
   2016         case CGA:
   2017           write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
   2018           break;
   2019         case LINEAR8:
   2020           write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
   2021           break;
   2022 #ifdef DEBUG
   2023         default:
   2024           unimplemented();
   2025 #endif
   2026        }
   2027      }
   2028     xcurs++;
   2029   }
   2030 
   2031  // Do we need to wrap ?
   2032  if(xcurs==nbcols)
   2033   {xcurs=0;
   2034    ycurs++;
   2035   }
   2036 
   2037  // Do we need to scroll ?
   2038  if(ycurs==nbrows)
   2039   {
   2040    if(vga_modes[line].class==TEXT)
   2041     {
   2042      address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
   2043      attr=read_byte(vga_modes[line].sstart,address+1);
   2044      biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
   2045     }
   2046    else
   2047     {
   2048      biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
   2049     }
   2050    ycurs-=1;
   2051   }
   2052 
   2053  // Set the cursor for the page
   2054  cursor=ycurs; cursor<<=8; cursor+=xcurs;
   2055  biosfn_set_cursor_pos(page,cursor);
   2056 }
   2057 
   2058 // --------------------------------------------------------------------------------------------
   2059 ASM_START
   2060 biosfn_get_video_mode:
   2061   push  ds
   2062   mov   ax, # BIOSMEM_SEG
   2063   mov   ds, ax
   2064   push  bx
   2065   mov   bx, # BIOSMEM_CURRENT_PAGE
   2066   mov   al, [bx]
   2067   pop   bx
   2068   mov   bh, al
   2069   push  bx
   2070   mov   bx, # BIOSMEM_VIDEO_CTL
   2071   mov   ah, [bx]
   2072   and   ah, #0x80
   2073   mov   bx, # BIOSMEM_CURRENT_MODE
   2074   mov   al, [bx]
   2075   or    al, ah
   2076   mov   bx, # BIOSMEM_NB_COLS
   2077   mov   ah, [bx]
   2078   pop   bx
   2079   pop   ds
   2080   ret
   2081 ASM_END
   2082 
   2083 // --------------------------------------------------------------------------------------------
   2084 ASM_START
   2085 biosfn_group_10:
   2086   cmp   al, #0x00
   2087   jne   int10_test_1001
   2088   jmp   biosfn_set_single_palette_reg
   2089 int10_test_1001:
   2090   cmp   al, #0x01
   2091   jne   int10_test_1002
   2092   jmp   biosfn_set_overscan_border_color
   2093 int10_test_1002:
   2094   cmp   al, #0x02
   2095   jne   int10_test_1003
   2096   jmp   biosfn_set_all_palette_reg
   2097 int10_test_1003:
   2098   cmp   al, #0x03
   2099   jne   int10_test_1007
   2100   jmp   biosfn_toggle_intensity
   2101 int10_test_1007:
   2102   cmp   al, #0x07
   2103   jne   int10_test_1008
   2104   jmp   biosfn_get_single_palette_reg
   2105 int10_test_1008:
   2106   cmp   al, #0x08
   2107   jne   int10_test_1009
   2108   jmp   biosfn_read_overscan_border_color
   2109 int10_test_1009:
   2110   cmp   al, #0x09
   2111   jne   int10_test_1010
   2112   jmp   biosfn_get_all_palette_reg
   2113 int10_test_1010:
   2114   cmp   al, #0x10
   2115   jne   int10_test_1012
   2116   jmp  biosfn_set_single_dac_reg
   2117 int10_test_1012:
   2118   cmp   al, #0x12
   2119   jne   int10_test_1013
   2120   jmp   biosfn_set_all_dac_reg
   2121 int10_test_1013:
   2122   cmp   al, #0x13
   2123   jne   int10_test_1015
   2124   jmp   biosfn_select_video_dac_color_page
   2125 int10_test_1015:
   2126   cmp   al, #0x15
   2127   jne   int10_test_1017
   2128   jmp   biosfn_read_single_dac_reg
   2129 int10_test_1017:
   2130   cmp   al, #0x17
   2131   jne   int10_test_1018
   2132   jmp   biosfn_read_all_dac_reg
   2133 int10_test_1018:
   2134   cmp   al, #0x18
   2135   jne   int10_test_1019
   2136   jmp   biosfn_set_pel_mask
   2137 int10_test_1019:
   2138   cmp   al, #0x19
   2139   jne   int10_test_101A
   2140   jmp   biosfn_read_pel_mask
   2141 int10_test_101A:
   2142   cmp   al, #0x1a
   2143   jne   int10_group_10_unknown
   2144   jmp   biosfn_read_video_dac_state
   2145 int10_group_10_unknown:
   2146 #ifdef DEBUG
   2147   call  _unknown
   2148 #endif
   2149   ret
   2150 
   2151 biosfn_set_single_palette_reg:
   2152   cmp   bl, #0x14
   2153   ja    no_actl_reg1
   2154   push  ax
   2155   push  dx
   2156   mov   dx, # VGAREG_ACTL_RESET
   2157   in    al, dx
   2158   mov   dx, # VGAREG_ACTL_ADDRESS
   2159   mov   al, bl
   2160   out   dx, al
   2161   mov   al, bh
   2162   out   dx, al
   2163   mov   al, #0x20
   2164   out   dx, al
   2165   pop   dx
   2166   pop   ax
   2167 no_actl_reg1:
   2168   ret
   2169 ASM_END
   2170 
   2171 // --------------------------------------------------------------------------------------------
   2172 ASM_START
   2173 biosfn_set_overscan_border_color:
   2174   push  bx
   2175   mov   bl, #0x11
   2176   call  biosfn_set_single_palette_reg
   2177   pop   bx
   2178   ret
   2179 ASM_END
   2180 
   2181 // --------------------------------------------------------------------------------------------
   2182 ASM_START
   2183 biosfn_set_all_palette_reg:
   2184   push  ax
   2185   push  bx
   2186   push  cx
   2187   push  dx
   2188   mov   bx, dx
   2189   mov   dx, # VGAREG_ACTL_RESET
   2190   in    al, dx
   2191   mov   cl, #0x00
   2192   mov   dx, # VGAREG_ACTL_ADDRESS
   2193 set_palette_loop:
   2194   mov   al, cl
   2195   out   dx, al
   2196   seg   es
   2197   mov   al, [bx]
   2198   out   dx, al
   2199   inc   bx
   2200   inc   cl
   2201   cmp   cl, #0x10
   2202   jne   set_palette_loop
   2203   mov   al, #0x11
   2204   out   dx, al
   2205   seg   es
   2206   mov   al, [bx]
   2207   out   dx, al
   2208   mov   al, #0x20
   2209   out   dx, al
   2210   pop   dx
   2211   pop   cx
   2212   pop   bx
   2213   pop   ax
   2214   ret
   2215 ASM_END
   2216 
   2217 // --------------------------------------------------------------------------------------------
   2218 ASM_START
   2219 biosfn_toggle_intensity:
   2220   push  ax
   2221   push  bx
   2222   push  dx
   2223   mov   dx, # VGAREG_ACTL_RESET
   2224   in    al, dx
   2225   mov   dx, # VGAREG_ACTL_ADDRESS
   2226   mov   al, #0x10
   2227   out   dx, al
   2228   mov   dx, # VGAREG_ACTL_READ_DATA
   2229   in    al, dx
   2230   and   al, #0xf7
   2231   and   bl, #0x01
   2232   shl   bl, 3
   2233   or    al, bl
   2234   mov   dx, # VGAREG_ACTL_ADDRESS
   2235   out   dx, al
   2236   mov   al, #0x20
   2237   out   dx, al
   2238   pop   dx
   2239   pop   bx
   2240   pop   ax
   2241   ret
   2242 ASM_END
   2243 
   2244 // --------------------------------------------------------------------------------------------
   2245 ASM_START
   2246 biosfn_get_single_palette_reg:
   2247   cmp   bl, #0x14
   2248   ja    no_actl_reg2
   2249   push  ax
   2250   push  dx
   2251   mov   dx, # VGAREG_ACTL_RESET
   2252   in    al, dx
   2253   mov   dx, # VGAREG_ACTL_ADDRESS
   2254   mov   al, bl
   2255   out   dx, al
   2256   mov   dx, # VGAREG_ACTL_READ_DATA
   2257   in    al, dx
   2258   mov   bh, al
   2259   mov   dx, # VGAREG_ACTL_RESET
   2260   in    al, dx
   2261   mov   dx, # VGAREG_ACTL_ADDRESS
   2262   mov   al, #0x20
   2263   out   dx, al
   2264   pop   dx
   2265   pop   ax
   2266 no_actl_reg2:
   2267   ret
   2268 ASM_END
   2269 
   2270 // --------------------------------------------------------------------------------------------
   2271 ASM_START
   2272 biosfn_read_overscan_border_color:
   2273   push  ax
   2274   push  bx
   2275   mov   bl, #0x11
   2276   call  biosfn_get_single_palette_reg
   2277   mov   al, bh
   2278   pop   bx
   2279   mov   bh, al
   2280   pop   ax
   2281   ret
   2282 ASM_END
   2283 
   2284 // --------------------------------------------------------------------------------------------
   2285 ASM_START
   2286 biosfn_get_all_palette_reg:
   2287   push  ax
   2288   push  bx
   2289   push  cx
   2290   push  dx
   2291   mov   bx, dx
   2292   mov   cl, #0x00
   2293 get_palette_loop:
   2294   mov   dx, # VGAREG_ACTL_RESET
   2295   in    al, dx
   2296   mov   dx, # VGAREG_ACTL_ADDRESS
   2297   mov   al, cl
   2298   out   dx, al
   2299   mov   dx, # VGAREG_ACTL_READ_DATA
   2300   in    al, dx
   2301   seg   es
   2302   mov   [bx], al
   2303   inc   bx
   2304   inc   cl
   2305   cmp   cl, #0x10
   2306   jne   get_palette_loop
   2307   mov   dx, # VGAREG_ACTL_RESET
   2308   in    al, dx
   2309   mov   dx, # VGAREG_ACTL_ADDRESS
   2310   mov   al, #0x11
   2311   out   dx, al
   2312   mov   dx, # VGAREG_ACTL_READ_DATA
   2313   in    al, dx
   2314   seg   es
   2315   mov   [bx], al
   2316   mov   dx, # VGAREG_ACTL_RESET
   2317   in    al, dx
   2318   mov   dx, # VGAREG_ACTL_ADDRESS
   2319   mov   al, #0x20
   2320   out   dx, al
   2321   pop   dx
   2322   pop   cx
   2323   pop   bx
   2324   pop   ax
   2325   ret
   2326 ASM_END
   2327 
   2328 // --------------------------------------------------------------------------------------------
   2329 ASM_START
   2330 biosfn_set_single_dac_reg:
   2331   push  ax
   2332   push  dx
   2333   mov   dx, # VGAREG_DAC_WRITE_ADDRESS
   2334   mov   al, bl
   2335   out   dx, al
   2336   mov   dx, # VGAREG_DAC_DATA
   2337   pop   ax
   2338   push  ax
   2339   mov   al, ah
   2340   out   dx, al
   2341   mov   al, ch
   2342   out   dx, al
   2343   mov   al, cl
   2344   out   dx, al
   2345   pop   dx
   2346   pop   ax
   2347   ret
   2348 ASM_END
   2349 
   2350 // --------------------------------------------------------------------------------------------
   2351 ASM_START
   2352 biosfn_set_all_dac_reg:
   2353   push  ax
   2354   push  bx
   2355   push  cx
   2356   push  dx
   2357   mov   dx, # VGAREG_DAC_WRITE_ADDRESS
   2358   mov   al, bl
   2359   out   dx, al
   2360   pop   dx
   2361   push  dx
   2362   mov   bx, dx
   2363   mov   dx, # VGAREG_DAC_DATA
   2364 set_dac_loop:
   2365   seg   es
   2366   mov   al, [bx]
   2367   out   dx, al
   2368   inc   bx
   2369   seg   es
   2370   mov   al, [bx]
   2371   out   dx, al
   2372   inc   bx
   2373   seg   es
   2374   mov   al, [bx]
   2375   out   dx, al
   2376   inc   bx
   2377   dec   cx
   2378   jnz   set_dac_loop
   2379   pop   dx
   2380   pop   cx
   2381   pop   bx
   2382   pop   ax
   2383   ret
   2384 ASM_END
   2385 
   2386 // --------------------------------------------------------------------------------------------
   2387 ASM_START
   2388 biosfn_select_video_dac_color_page:
   2389   push  ax
   2390   push  bx
   2391   push  dx
   2392   mov   dx, # VGAREG_ACTL_RESET
   2393   in    al, dx
   2394   mov   dx, # VGAREG_ACTL_ADDRESS
   2395   mov   al, #0x10
   2396   out   dx, al
   2397   mov   dx, # VGAREG_ACTL_READ_DATA
   2398   in    al, dx
   2399   and   bl, #0x01
   2400   jnz   set_dac_page
   2401   and   al, #0x7f
   2402   shl   bh, 7
   2403   or    al, bh
   2404   mov   dx, # VGAREG_ACTL_ADDRESS
   2405   out   dx, al
   2406   jmp   set_actl_normal
   2407 set_dac_page:
   2408   push  ax
   2409   mov   dx, # VGAREG_ACTL_RESET
   2410   in    al, dx
   2411   mov   dx, # VGAREG_ACTL_ADDRESS
   2412   mov   al, #0x14
   2413   out   dx, al
   2414   pop   ax
   2415   and   al, #0x80
   2416   jnz   set_dac_16_page
   2417   shl   bh, 2
   2418 set_dac_16_page:
   2419   and   bh, #0x0f
   2420   mov   al, bh
   2421   out   dx, al
   2422 set_actl_normal:
   2423   mov   al, #0x20
   2424   out   dx, al
   2425   pop   dx
   2426   pop   bx
   2427   pop   ax
   2428   ret
   2429 ASM_END
   2430 
   2431 // --------------------------------------------------------------------------------------------
   2432 ASM_START
   2433 biosfn_read_single_dac_reg:
   2434   push  ax
   2435   push  dx
   2436   mov   dx, # VGAREG_DAC_READ_ADDRESS
   2437   mov   al, bl
   2438   out   dx, al
   2439   pop   ax
   2440   mov   ah, al
   2441   mov   dx, # VGAREG_DAC_DATA
   2442   in    al, dx
   2443   xchg  al, ah
   2444   push  ax
   2445   in    al, dx
   2446   mov   ch, al
   2447   in    al, dx
   2448   mov   cl, al
   2449   pop   dx
   2450   pop   ax
   2451   ret
   2452 ASM_END
   2453 
   2454 // --------------------------------------------------------------------------------------------
   2455 ASM_START
   2456 biosfn_read_all_dac_reg:
   2457   push  ax
   2458   push  bx
   2459   push  cx
   2460   push  dx
   2461   mov   dx, # VGAREG_DAC_READ_ADDRESS
   2462   mov   al, bl
   2463   out   dx, al
   2464   pop   dx
   2465   push  dx
   2466   mov   bx, dx
   2467   mov   dx, # VGAREG_DAC_DATA
   2468 read_dac_loop:
   2469   in    al, dx
   2470   seg   es
   2471   mov   [bx], al
   2472   inc   bx
   2473   in    al, dx
   2474   seg   es
   2475   mov   [bx], al
   2476   inc   bx
   2477   in    al, dx
   2478   seg   es
   2479   mov   [bx], al
   2480   inc   bx
   2481   dec   cx
   2482   jnz   read_dac_loop
   2483   pop   dx
   2484   pop   cx
   2485   pop   bx
   2486   pop   ax
   2487   ret
   2488 ASM_END
   2489 
   2490 // --------------------------------------------------------------------------------------------
   2491 ASM_START
   2492 biosfn_set_pel_mask:
   2493   push  ax
   2494   push  dx
   2495   mov   dx, # VGAREG_PEL_MASK
   2496   mov   al, bl
   2497   out   dx, al
   2498   pop   dx
   2499   pop   ax
   2500   ret
   2501 ASM_END
   2502 
   2503 // --------------------------------------------------------------------------------------------
   2504 ASM_START
   2505 biosfn_read_pel_mask:
   2506   push  ax
   2507   push  dx
   2508   mov   dx, # VGAREG_PEL_MASK
   2509   in    al, dx
   2510   mov   bl, al
   2511   pop   dx
   2512   pop   ax
   2513   ret
   2514 ASM_END
   2515 
   2516 // --------------------------------------------------------------------------------------------
   2517 ASM_START
   2518 biosfn_read_video_dac_state:
   2519   push  ax
   2520   push  dx
   2521   mov   dx, # VGAREG_ACTL_RESET
   2522   in    al, dx
   2523   mov   dx, # VGAREG_ACTL_ADDRESS
   2524   mov   al, #0x10
   2525   out   dx, al
   2526   mov   dx, # VGAREG_ACTL_READ_DATA
   2527   in    al, dx
   2528   mov   bl, al
   2529   shr   bl, 7
   2530   mov   dx, # VGAREG_ACTL_RESET
   2531   in    al, dx
   2532   mov   dx, # VGAREG_ACTL_ADDRESS
   2533   mov   al, #0x14
   2534   out   dx, al
   2535   mov   dx, # VGAREG_ACTL_READ_DATA
   2536   in    al, dx
   2537   mov   bh, al
   2538   and   bh, #0x0f
   2539   test  bl, #0x01
   2540   jnz   get_dac_16_page
   2541   shr   bh, 2
   2542 get_dac_16_page:
   2543   mov   dx, # VGAREG_ACTL_RESET
   2544   in    al, dx
   2545   mov   dx, # VGAREG_ACTL_ADDRESS
   2546   mov   al, #0x20
   2547   out   dx, al
   2548   pop   dx
   2549   pop   ax
   2550   ret
   2551 ASM_END
   2552 
   2553 // --------------------------------------------------------------------------------------------
   2554 static void biosfn_perform_gray_scale_summing (start,count)
   2555 Bit16u start;Bit16u count;
   2556 {Bit8u r,g,b;
   2557  Bit16u i;
   2558  Bit16u index;
   2559 
   2560  inb(VGAREG_ACTL_RESET);
   2561  outb(VGAREG_ACTL_ADDRESS,0x00);
   2562 
   2563  for( index = 0; index < count; index++ )
   2564   {
   2565    // set read address and switch to read mode
   2566    outb(VGAREG_DAC_READ_ADDRESS,start);
   2567    // get 6-bit wide RGB data values
   2568    r=inb( VGAREG_DAC_DATA );
   2569    g=inb( VGAREG_DAC_DATA );
   2570    b=inb( VGAREG_DAC_DATA );
   2571 
   2572    // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
   2573    i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
   2574 
   2575    if(i>0x3f)i=0x3f;
   2576 
   2577    // set write address and switch to write mode
   2578    outb(VGAREG_DAC_WRITE_ADDRESS,start);
   2579    // write new intensity value
   2580    outb( VGAREG_DAC_DATA, i&0xff );
   2581    outb( VGAREG_DAC_DATA, i&0xff );
   2582    outb( VGAREG_DAC_DATA, i&0xff );
   2583    start++;
   2584   }
   2585  inb(VGAREG_ACTL_RESET);
   2586  outb(VGAREG_ACTL_ADDRESS,0x20);
   2587 }
   2588 
   2589 // --------------------------------------------------------------------------------------------
   2590 static void get_font_access()
   2591 {
   2592 ASM_START
   2593  mov dx, # VGAREG_SEQU_ADDRESS
   2594  mov ax, #0x0100
   2595  out dx, ax
   2596  mov ax, #0x0402
   2597  out dx, ax
   2598  mov ax, #0x0704
   2599  out dx, ax
   2600  mov ax, #0x0300
   2601  out dx, ax
   2602  mov dx, # VGAREG_GRDC_ADDRESS
   2603  mov ax, #0x0204
   2604  out dx, ax
   2605  mov ax, #0x0005
   2606  out dx, ax
   2607  mov ax, #0x0406
   2608  out dx, ax
   2609 ASM_END
   2610 }
   2611 
   2612 static void release_font_access()
   2613 {
   2614 ASM_START
   2615  mov dx, # VGAREG_SEQU_ADDRESS
   2616  mov ax, #0x0100
   2617  out dx, ax
   2618  mov ax, #0x0302
   2619  out dx, ax
   2620  mov ax, #0x0304
   2621  out dx, ax
   2622  mov ax, #0x0300
   2623  out dx, ax
   2624  mov dx, # VGAREG_READ_MISC_OUTPUT
   2625  in  al, dx
   2626  and al, #0x01
   2627  shl al, 2
   2628  or  al, #0x0a
   2629  mov ah, al
   2630  mov al, #0x06
   2631  mov dx, # VGAREG_GRDC_ADDRESS
   2632  out dx, ax
   2633  mov ax, #0x0004
   2634  out dx, ax
   2635  mov ax, #0x1005
   2636  out dx, ax
   2637 ASM_END
   2638 }
   2639 
   2640 ASM_START
   2641 idiv_u:
   2642   xor dx,dx
   2643   div bx
   2644   ret
   2645 ASM_END
   2646 
   2647 static void set_scan_lines(lines) Bit8u lines;
   2648 {
   2649  Bit16u crtc_addr,cols,page,vde;
   2650  Bit8u crtc_r9,ovl,rows;
   2651 
   2652  crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
   2653  outb(crtc_addr, 0x09);
   2654  crtc_r9 = inb(crtc_addr+1);
   2655  crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
   2656  outb(crtc_addr+1, crtc_r9);
   2657  if(lines==8)
   2658   {
   2659    biosfn_set_cursor_shape(0x06,0x07);
   2660   }
   2661  else
   2662   {
   2663    biosfn_set_cursor_shape(lines-4,lines-3);
   2664   }
   2665  write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
   2666  outb(crtc_addr, 0x12);
   2667  vde = inb(crtc_addr+1);
   2668  outb(crtc_addr, 0x07);
   2669  ovl = inb(crtc_addr+1);
   2670  vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
   2671  rows = vde / lines;
   2672  write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
   2673  cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
   2674  write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
   2675 }
   2676 
   2677 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;
   2678 {
   2679  Bit16u blockaddr,dest,i,src;
   2680 
   2681  get_font_access();
   2682  blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
   2683  for(i=0;i<CX;i++)
   2684   {
   2685    src = BP + i * BH;
   2686    dest = blockaddr + (DX + i) * 32;
   2687    memcpyb(0xA000, dest, ES, src, BH);
   2688   }
   2689  release_font_access();
   2690  if(AL>=0x10)
   2691   {
   2692    set_scan_lines(BH);
   2693   }
   2694 }
   2695 
   2696 static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL;
   2697 {
   2698  Bit16u blockaddr,dest,i,src;
   2699 
   2700  get_font_access();
   2701  blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
   2702  for(i=0;i<0x100;i++)
   2703   {
   2704    src = i * 14;
   2705    dest = blockaddr + i * 32;
   2706    memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14);
   2707   }
   2708  release_font_access();
   2709  if(AL>=0x10)
   2710   {
   2711    set_scan_lines(14);
   2712   }
   2713 }
   2714 
   2715 static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL;
   2716 {
   2717  Bit16u blockaddr,dest,i,src;
   2718 
   2719  get_font_access();
   2720  blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
   2721  for(i=0;i<0x100;i++)
   2722   {
   2723    src = i * 8;
   2724    dest = blockaddr + i * 32;
   2725    memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8);
   2726   }
   2727  release_font_access();
   2728  if(AL>=0x10)
   2729   {
   2730    set_scan_lines(8);
   2731   }
   2732 }
   2733 
   2734 // --------------------------------------------------------------------------------------------
   2735 ASM_START
   2736 biosfn_set_text_block_specifier:
   2737   push  ax
   2738   push  dx
   2739   mov   dx, # VGAREG_SEQU_ADDRESS
   2740   mov   ah, bl
   2741   mov   al, #0x03
   2742   out   dx, ax
   2743   pop   dx
   2744   pop   ax
   2745   ret
   2746 ASM_END
   2747 
   2748 // --------------------------------------------------------------------------------------------
   2749 static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL;
   2750 {
   2751  Bit16u blockaddr,dest,i,src;
   2752 
   2753  get_font_access();
   2754  blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
   2755  for(i=0;i<0x100;i++)
   2756   {
   2757    src = i * 16;
   2758    dest = blockaddr + i * 32;
   2759    memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16);
   2760   }
   2761  release_font_access();
   2762  if(AL>=0x10)
   2763   {
   2764    set_scan_lines(16);
   2765   }
   2766 }
   2767 
   2768 static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
   2769 {
   2770 #ifdef DEBUG
   2771  unimplemented();
   2772 #endif
   2773 }
   2774 static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL;
   2775 {
   2776 #ifdef DEBUG
   2777  unimplemented();
   2778 #endif
   2779 }
   2780 static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
   2781 {
   2782 #ifdef DEBUG
   2783  unimplemented();
   2784 #endif
   2785 }
   2786 static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
   2787 {
   2788 #ifdef DEBUG
   2789  unimplemented();
   2790 #endif
   2791 }
   2792 static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
   2793 {
   2794 #ifdef DEBUG
   2795  unimplemented();
   2796 #endif
   2797 }
   2798 // --------------------------------------------------------------------------------------------
   2799 static void biosfn_get_font_info (BH,ES,BP,CX,DX)
   2800 Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX;
   2801 {Bit16u ss=get_SS();
   2802 
   2803  switch(BH)
   2804   {case 0x00:
   2805     write_word(ss,ES,read_word(0x00,0x1f*4));
   2806     write_word(ss,BP,read_word(0x00,(0x1f*4)+2));
   2807     break;
   2808    case 0x01:
   2809     write_word(ss,ES,read_word(0x00,0x43*4));
   2810     write_word(ss,BP,read_word(0x00,(0x43*4)+2));
   2811     break;
   2812    case 0x02:
   2813     write_word(ss,ES,0xC000);
   2814     write_word(ss,BP,vgafont14);
   2815     break;
   2816    case 0x03:
   2817     write_word(ss,ES,0xC000);
   2818     write_word(ss,BP,vgafont8);
   2819     break;
   2820    case 0x04:
   2821     write_word(ss,ES,0xC000);
   2822     write_word(ss,BP,vgafont8+128*8);
   2823     break;
   2824    case 0x05:
   2825     write_word(ss,ES,0xC000);
   2826     write_word(ss,BP,vgafont14alt);
   2827     break;
   2828    case 0x06:
   2829     write_word(ss,ES,0xC000);
   2830     write_word(ss,BP,vgafont16);
   2831     break;
   2832    case 0x07:
   2833     write_word(ss,ES,0xC000);
   2834     write_word(ss,BP,vgafont16alt);
   2835     break;
   2836    default:
   2837     #ifdef DEBUG
   2838      printf("Get font info BH(%02x) was discarded\n",BH);
   2839     #endif
   2840     return;
   2841   }
   2842  // Set byte/char of on screen font
   2843  write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT));
   2844 
   2845  // Set Highest char row
   2846  write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS));
   2847 }
   2848 
   2849 // --------------------------------------------------------------------------------------------
   2850 ASM_START
   2851 biosfn_get_ega_info:
   2852   push  ds
   2853   push  ax
   2854   mov   ax, # BIOSMEM_SEG
   2855   mov   ds, ax
   2856   xor   ch, ch
   2857   mov   bx, # BIOSMEM_SWITCHES
   2858   mov   cl, [bx]
   2859   and   cl, #0x0f
   2860   mov   bx, # BIOSMEM_CRTC_ADDRESS
   2861   mov   ax, [bx]
   2862   mov   bx, #0x0003
   2863   cmp   ax, # VGAREG_MDA_CRTC_ADDRESS
   2864   jne   mode_ega_color
   2865   mov   bh, #0x01
   2866 mode_ega_color:
   2867   pop   ax
   2868   pop   ds
   2869   ret
   2870 ASM_END
   2871 
   2872 // --------------------------------------------------------------------------------------------
   2873 static void biosfn_alternate_prtsc()
   2874 {
   2875 #ifdef DEBUG
   2876  unimplemented();
   2877 #endif
   2878 }
   2879 
   2880 // --------------------------------------------------------------------------------------------
   2881 ASM_START
   2882 biosfn_select_vert_res:
   2883 
   2884 ; res : 00 200 lines, 01 350 lines, 02 400 lines
   2885 
   2886   push  ds
   2887   push  bx
   2888   push  dx
   2889   mov   dl, al
   2890   mov   ax, # BIOSMEM_SEG
   2891   mov   ds, ax
   2892   mov   bx, # BIOSMEM_MODESET_CTL
   2893   mov   al, [bx]
   2894   mov   bx, # BIOSMEM_SWITCHES
   2895   mov   ah, [bx]
   2896   cmp   dl, #0x01
   2897   je    vert_res_350
   2898   jb    vert_res_200
   2899   cmp   dl, #0x02
   2900   je    vert_res_400
   2901 #ifdef DEBUG
   2902   mov   al, dl
   2903   xor   ah, ah
   2904   push  ax
   2905   mov   bx, #msg_vert_res
   2906   push  bx
   2907   call  _printf
   2908   add   sp, #4
   2909 #endif
   2910   jmp   set_retcode
   2911 vert_res_400:
   2912 
   2913   ; reset modeset ctl bit 7 and set bit 4
   2914   ; set switches bit 3-0 to 0x09
   2915 
   2916   and   al, #0x7f
   2917   or    al, #0x10
   2918   and   ah, #0xf0
   2919   or    ah, #0x09
   2920   jnz   set_vert_res
   2921 vert_res_350:
   2922 
   2923   ; reset modeset ctl bit 7 and bit 4
   2924   ; set switches bit 3-0 to 0x09
   2925 
   2926   and   al, #0x6f
   2927   and   ah, #0xf0
   2928   or    ah, #0x09
   2929   jnz   set_vert_res
   2930 vert_res_200:
   2931 
   2932   ; set modeset ctl bit 7 and reset bit 4
   2933   ; set switches bit 3-0 to 0x08
   2934 
   2935   and   al, #0xef
   2936   or    al, #0x80
   2937   and   ah, #0xf0
   2938   or    ah, #0x08
   2939 set_vert_res:
   2940   mov   bx, # BIOSMEM_MODESET_CTL
   2941   mov   [bx], al
   2942   mov   bx, # BIOSMEM_SWITCHES
   2943   mov   [bx], ah
   2944 set_retcode:
   2945   mov   ax, #0x1212
   2946   pop   dx
   2947   pop   bx
   2948   pop   ds
   2949   ret
   2950 
   2951 #ifdef DEBUG
   2952 msg_vert_res:
   2953 .ascii "Select vert res (%02x) was discarded"
   2954 .byte 0x0d,0x0a,0x00
   2955 #endif
   2956 
   2957 
   2958 biosfn_enable_default_palette_loading:
   2959   push  ds
   2960   push  bx
   2961   push  dx
   2962   mov   dl, al
   2963   and   dl, #0x01
   2964   shl   dl, 3
   2965   mov   ax, # BIOSMEM_SEG
   2966   mov   ds, ax
   2967   mov   bx, # BIOSMEM_MODESET_CTL
   2968   mov   al, [bx]
   2969   and   al, #0xf7
   2970   or    al, dl
   2971   mov   [bx], al
   2972   mov   ax, #0x1212
   2973   pop   dx
   2974   pop   bx
   2975   pop   ds
   2976   ret
   2977 
   2978 
   2979 biosfn_enable_video_addressing:
   2980   push  bx
   2981   push  dx
   2982   mov   bl, al
   2983   and   bl, #0x01
   2984   xor   bl, #0x01
   2985   shl   bl, 1
   2986   mov   dx, # VGAREG_READ_MISC_OUTPUT
   2987   in    al, dx
   2988   and   al, #0xfd
   2989   or    al, bl
   2990   mov   dx, # VGAREG_WRITE_MISC_OUTPUT
   2991   out   dx, al
   2992   mov   ax, #0x1212
   2993   pop   dx
   2994   pop   bx
   2995   ret
   2996 
   2997 
   2998 biosfn_enable_grayscale_summing:
   2999   push  ds
   3000   push  bx
   3001   push  dx
   3002   mov   dl, al
   3003   and   dl, #0x01
   3004   xor   dl, #0x01
   3005   shl   dl, 1
   3006   mov   ax, # BIOSMEM_SEG
   3007   mov   ds, ax
   3008   mov   bx, # BIOSMEM_MODESET_CTL
   3009   mov   al, [bx]
   3010   and   al, #0xfd
   3011   or    al, dl
   3012   mov   [bx], al
   3013   mov   ax, #0x1212
   3014   pop   dx
   3015   pop   bx
   3016   pop   ds
   3017   ret
   3018 
   3019 
   3020 biosfn_enable_cursor_emulation:
   3021   push  ds
   3022   push  bx
   3023   push  dx
   3024   mov   dl, al
   3025   and   dl, #0x01
   3026   xor   dl, #0x01
   3027   mov   ax, # BIOSMEM_SEG
   3028   mov   ds, ax
   3029   mov   bx, # BIOSMEM_MODESET_CTL
   3030   mov   al, [bx]
   3031   and   al, #0xfe
   3032   or    al, dl
   3033   mov   [bx], al
   3034   mov   ax, #0x1212
   3035   pop   dx
   3036   pop   bx
   3037   pop   ds
   3038   ret
   3039 ASM_END
   3040 
   3041 // --------------------------------------------------------------------------------------------
   3042 static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
   3043 {
   3044 #ifdef DEBUG
   3045  unimplemented();
   3046 #endif
   3047 }
   3048 static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
   3049 {
   3050 #ifdef DEBUG
   3051  unimplemented();
   3052 #endif
   3053 }
   3054 
   3055 // --------------------------------------------------------------------------------------------
   3056 static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset)
   3057 Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset;
   3058 {
   3059  Bit16u newcurs,oldcurs,dummy;
   3060  Bit8u car,carattr;
   3061 
   3062  // Read curs info for the page
   3063  biosfn_get_cursor_pos(page,&dummy,&oldcurs);
   3064 
   3065  // if row=0xff special case : use current cursor position
   3066  if(row==0xff)
   3067   {col=oldcurs&0x00ff;
   3068    row=(oldcurs&0xff00)>>8;
   3069   }
   3070 
   3071  newcurs=row; newcurs<<=8; newcurs+=col;
   3072  biosfn_set_cursor_pos(page,newcurs);
   3073 
   3074  while(count--!=0)
   3075   {
   3076    car=read_byte(seg,offset++);
   3077    if((flag&0x02)!=0)
   3078     attr=read_byte(seg,offset++);
   3079 
   3080    biosfn_write_teletype(car,page,attr,WITH_ATTR);
   3081   }
   3082 
   3083  // Set back curs pos
   3084  if((flag&0x01)==0)
   3085   biosfn_set_cursor_pos(page,oldcurs);
   3086 }
   3087 
   3088 // --------------------------------------------------------------------------------------------
   3089 ASM_START
   3090 biosfn_group_1A:
   3091   cmp   al, #0x00
   3092   je    biosfn_read_display_code
   3093   cmp   al, #0x01
   3094   je    biosfn_set_display_code
   3095 #ifdef DEBUG
   3096   call  _unknown
   3097 #endif
   3098   ret
   3099 biosfn_read_display_code:
   3100   push  ds
   3101   push  ax
   3102   mov   ax, # BIOSMEM_SEG
   3103   mov   ds, ax
   3104   mov   bx, # BIOSMEM_DCC_INDEX
   3105   mov   al, [bx]
   3106   mov   bl, al
   3107   xor   bh, bh
   3108   pop   ax
   3109   mov   al, ah
   3110   pop   ds
   3111   ret
   3112 biosfn_set_display_code:
   3113   push  ds
   3114   push  ax
   3115   push  bx
   3116   mov   ax, # BIOSMEM_SEG
   3117   mov   ds, ax
   3118   mov   ax, bx
   3119   mov   bx, # BIOSMEM_DCC_INDEX
   3120   mov   [bx], al
   3121 #ifdef DEBUG
   3122   mov   al, ah
   3123   xor   ah, ah
   3124   push  ax
   3125   mov   bx, #msg_alt_dcc
   3126   push  bx
   3127   call  _printf
   3128   add   sp, #4
   3129 #endif
   3130   pop   bx
   3131   pop   ax
   3132   mov   al, ah
   3133   pop   ds
   3134   ret
   3135 
   3136 #ifdef DEBUG
   3137 msg_alt_dcc:
   3138 .ascii "Alternate Display code (%02x) was discarded"
   3139 .byte 0x0d,0x0a,0x00
   3140 #endif
   3141 ASM_END
   3142 
   3143 // --------------------------------------------------------------------------------------------
   3144 static void biosfn_read_state_info (BX,ES,DI)
   3145 Bit16u BX;Bit16u ES;Bit16u DI;
   3146 {
   3147  // Address of static functionality table
   3148  write_word(ES,DI+0x00,&static_functionality);
   3149  write_word(ES,DI+0x02,0xC000);
   3150 
   3151  // Hard coded copy from BIOS area. Should it be cleaner ?
   3152  memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
   3153  memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
   3154 
   3155  write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
   3156  write_byte(ES,DI+0x26,0);
   3157  write_byte(ES,DI+0x27,16);
   3158  write_byte(ES,DI+0x28,0);
   3159  write_byte(ES,DI+0x29,8);
   3160  write_byte(ES,DI+0x2a,2);
   3161  write_byte(ES,DI+0x2b,0);
   3162  write_byte(ES,DI+0x2c,0);
   3163  write_byte(ES,DI+0x31,3);
   3164  write_byte(ES,DI+0x32,0);
   3165 
   3166  memsetb(ES,DI+0x33,0,13);
   3167 }
   3168 
   3169 // --------------------------------------------------------------------------------------------
   3170 // --------------------------------------------------------------------------------------------
   3171 static Bit16u biosfn_read_video_state_size2 (CX)
   3172      Bit16u CX;
   3173 {
   3174     Bit16u size;
   3175     size = 0;
   3176     if (CX & 1) {
   3177         size += 0x46;
   3178     }
   3179     if (CX & 2) {
   3180         size += (5 + 8 + 5) * 2 + 6;
   3181     }
   3182     if (CX & 4) {
   3183         size += 3 + 256 * 3 + 1;
   3184 }
   3185     return size;
   3186 }
   3187 
   3188 static void biosfn_read_video_state_size (CX, BX)
   3189      Bit16u CX; Bit16u *BX;
   3190 {
   3191     Bit16u ss=get_SS();
   3192     write_word(ss, BX, biosfn_read_video_state_size2(CX));
   3193 }
   3194 
   3195 static Bit16u biosfn_save_video_state (CX,ES,BX)
   3196      Bit16u CX;Bit16u ES;Bit16u BX;
   3197 {
   3198     Bit16u i, v, crtc_addr, ar_index;
   3199 
   3200     crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
   3201     if (CX & 1) {
   3202         write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
   3203         write_byte(ES, BX, inb(crtc_addr)); BX++;
   3204         write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
   3205         inb(VGAREG_ACTL_RESET);
   3206         ar_index = inb(VGAREG_ACTL_ADDRESS);
   3207         write_byte(ES, BX, ar_index); BX++;
   3208         write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
   3209 
   3210         for(i=1;i<=4;i++){
   3211             outb(VGAREG_SEQU_ADDRESS, i);
   3212             write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
   3213         }
   3214         outb(VGAREG_SEQU_ADDRESS, 0);
   3215         write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
   3216 
   3217         for(i=0;i<=0x18;i++) {
   3218             outb(crtc_addr,i);
   3219             write_byte(ES, BX, inb(crtc_addr+1)); BX++;
   3220         }
   3221 
   3222         for(i=0;i<=0x13;i++) {
   3223             inb(VGAREG_ACTL_RESET);
   3224             outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
   3225             write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
   3226         }
   3227         inb(VGAREG_ACTL_RESET);
   3228 
   3229         for(i=0;i<=8;i++) {
   3230             outb(VGAREG_GRDC_ADDRESS,i);
   3231             write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
   3232         }
   3233 
   3234         write_word(ES, BX, crtc_addr); BX+= 2;
   3235 
   3236         /* XXX: read plane latches */
   3237         write_byte(ES, BX, 0); BX++;
   3238         write_byte(ES, BX, 0); BX++;
   3239         write_byte(ES, BX, 0); BX++;
   3240         write_byte(ES, BX, 0); BX++;
   3241     }
   3242     if (CX & 2) {
   3243         write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
   3244         write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
   3245         write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
   3246         write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
   3247         write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
   3248         write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
   3249         write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
   3250         write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
   3251         write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
   3252         write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
   3253         for(i=0;i<8;i++) {
   3254             write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
   3255             BX += 2;
   3256         }
   3257         write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
   3258         write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
   3259         /* current font */
   3260         write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
   3261         write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
   3262         write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
   3263         write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
   3264     }
   3265     if (CX & 4) {
   3266         /* XXX: check this */
   3267         write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
   3268         write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
   3269         write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
   3270         // Set the whole dac always, from 0
   3271         outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
   3272         for(i=0;i<256*3;i++) {
   3273             write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
   3274         }
   3275         write_byte(ES, BX, 0); BX++; /* color select register */
   3276     }
   3277     return BX;
   3278 }
   3279 
   3280 static Bit16u biosfn_restore_video_state (CX,ES,BX)
   3281      Bit16u CX;Bit16u ES;Bit16u BX;
   3282 {
   3283     Bit16u i, crtc_addr, v, addr1, ar_index;
   3284 
   3285     if (CX & 1) {
   3286         // Reset Attribute Ctl flip-flop
   3287         inb(VGAREG_ACTL_RESET);
   3288 
   3289         crtc_addr = read_word(ES, BX + 0x40);
   3290         addr1 = BX;
   3291         BX += 5;
   3292 
   3293         for(i=1;i<=4;i++){
   3294             outb(VGAREG_SEQU_ADDRESS, i);
   3295             outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
   3296         }
   3297         outb(VGAREG_SEQU_ADDRESS, 0);
   3298         outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
   3299 
   3300         // Disable CRTC write protection
   3301         outw(crtc_addr,0x0011);
   3302         // Set CRTC regs
   3303         for(i=0;i<=0x18;i++) {
   3304             if (i != 0x11) {
   3305                 outb(crtc_addr,i);
   3306                 outb(crtc_addr+1, read_byte(ES, BX));
   3307             }
   3308             BX++;
   3309         }
   3310         // select crtc base address
   3311         v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
   3312         if (crtc_addr = 0x3d4)
   3313             v |= 0x01;
   3314         outb(VGAREG_WRITE_MISC_OUTPUT, v);
   3315 
   3316         // enable write protection if needed
   3317         outb(crtc_addr, 0x11);
   3318         outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
   3319 
   3320         // Set Attribute Ctl
   3321         ar_index = read_byte(ES, addr1 + 0x03);
   3322         inb(VGAREG_ACTL_RESET);
   3323         for(i=0;i<=0x13;i++) {
   3324             outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
   3325             outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
   3326         }
   3327         outb(VGAREG_ACTL_ADDRESS, ar_index);
   3328         inb(VGAREG_ACTL_RESET);
   3329 
   3330         for(i=0;i<=8;i++) {
   3331             outb(VGAREG_GRDC_ADDRESS,i);
   3332             outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
   3333         }
   3334         BX += 2; /* crtc_addr */
   3335         BX += 4; /* plane latches */
   3336 
   3337         outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
   3338         outb(crtc_addr, read_byte(ES, addr1)); addr1++;
   3339         outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
   3340         addr1++;
   3341         outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
   3342     }
   3343     if (CX & 2) {
   3344         write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
   3345         write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
   3346         write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
   3347         write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
   3348         write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
   3349         write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
   3350         write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
   3351         write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
   3352         write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
   3353         write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
   3354         for(i=0;i<8;i++) {
   3355             write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
   3356             BX += 2;
   3357         }
   3358         write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
   3359         write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
   3360         /* current font */
   3361         write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
   3362         write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
   3363         write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
   3364         write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
   3365     }
   3366     if (CX & 4) {
   3367         BX++;
   3368         v = read_byte(ES, BX); BX++;
   3369         outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
   3370         // Set the whole dac always, from 0
   3371         outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
   3372         for(i=0;i<256*3;i++) {
   3373             outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
   3374         }
   3375         BX++;
   3376         outb(VGAREG_DAC_WRITE_ADDRESS, v);
   3377     }
   3378     return BX;
   3379 }
   3380 
   3381 // ============================================================================================
   3382 //
   3383 // Video Utils
   3384 //
   3385 // ============================================================================================
   3386 
   3387 // --------------------------------------------------------------------------------------------
   3388 static Bit8u find_vga_entry(mode)
   3389 Bit8u mode;
   3390 {
   3391  Bit8u i,line=0xFF;
   3392  for(i=0;i<=MODE_MAX;i++)
   3393   if(vga_modes[i].svgamode==mode)
   3394    {line=i;
   3395     break;
   3396    }
   3397  return line;
   3398 }
   3399 
   3400 /* =========================================================== */
   3401 /*
   3402  * Misc Utils
   3403 */
   3404 /* =========================================================== */
   3405 
   3406 // --------------------------------------------------------------------------------------------
   3407 static void memsetb(seg,offset,value,count)
   3408   Bit16u seg;
   3409   Bit16u offset;
   3410   Bit16u value;
   3411   Bit16u count;
   3412 {
   3413 ASM_START
   3414   push bp
   3415   mov  bp, sp
   3416 
   3417     push ax
   3418     push cx
   3419     push es
   3420     push di
   3421 
   3422     mov  cx, 10[bp] ; count
   3423     cmp  cx, #0x00
   3424     je   memsetb_end
   3425     mov  ax, 4[bp] ; segment
   3426     mov  es, ax
   3427     mov  ax, 6[bp] ; offset
   3428     mov  di, ax
   3429     mov  al, 8[bp] ; value
   3430     cld
   3431     rep
   3432      stosb
   3433 
   3434 memsetb_end:
   3435     pop di
   3436     pop es
   3437     pop cx
   3438     pop ax
   3439 
   3440   pop bp
   3441 ASM_END
   3442 }
   3443 
   3444 // --------------------------------------------------------------------------------------------
   3445 static void memsetw(seg,offset,value,count)
   3446   Bit16u seg;
   3447   Bit16u offset;
   3448   Bit16u value;
   3449   Bit16u count;
   3450 {
   3451 ASM_START
   3452   push bp
   3453   mov  bp, sp
   3454 
   3455     push ax
   3456     push cx
   3457     push es
   3458     push di
   3459 
   3460     mov  cx, 10[bp] ; count
   3461     cmp  cx, #0x00
   3462     je   memsetw_end
   3463     mov  ax, 4[bp] ; segment
   3464     mov  es, ax
   3465     mov  ax, 6[bp] ; offset
   3466     mov  di, ax
   3467     mov  ax, 8[bp] ; value
   3468     cld
   3469     rep
   3470      stosw
   3471 
   3472 memsetw_end:
   3473     pop di
   3474     pop es
   3475     pop cx
   3476     pop ax
   3477 
   3478   pop bp
   3479 ASM_END
   3480 }
   3481 
   3482 // --------------------------------------------------------------------------------------------
   3483 static void memcpyb(dseg,doffset,sseg,soffset,count)
   3484   Bit16u dseg;
   3485   Bit16u doffset;
   3486   Bit16u sseg;
   3487   Bit16u soffset;
   3488   Bit16u count;
   3489 {
   3490 ASM_START
   3491   push bp
   3492   mov  bp, sp
   3493 
   3494     push ax
   3495     push cx
   3496     push es
   3497     push di
   3498     push ds
   3499     push si
   3500 
   3501     mov  cx, 12[bp] ; count
   3502     cmp  cx, #0x0000
   3503     je   memcpyb_end
   3504     mov  ax, 4[bp] ; dsegment
   3505     mov  es, ax
   3506     mov  ax, 6[bp] ; doffset
   3507     mov  di, ax
   3508     mov  ax, 8[bp] ; ssegment
   3509     mov  ds, ax
   3510     mov  ax, 10[bp] ; soffset
   3511     mov  si, ax
   3512     cld
   3513     rep
   3514      movsb
   3515 
   3516 memcpyb_end:
   3517     pop si
   3518     pop ds
   3519     pop di
   3520     pop es
   3521     pop cx
   3522     pop ax
   3523 
   3524   pop bp
   3525 ASM_END
   3526 }
   3527 
   3528 // --------------------------------------------------------------------------------------------
   3529 static void memcpyw(dseg,doffset,sseg,soffset,count)
   3530   Bit16u dseg;
   3531   Bit16u doffset;
   3532   Bit16u sseg;
   3533   Bit16u soffset;
   3534   Bit16u count;
   3535 {
   3536 ASM_START
   3537   push bp
   3538   mov  bp, sp
   3539 
   3540     push ax
   3541     push cx
   3542     push es
   3543     push di
   3544     push ds
   3545     push si
   3546 
   3547     mov  cx, 12[bp] ; count
   3548     cmp  cx, #0x0000
   3549     je   memcpyw_end
   3550     mov  ax, 4[bp] ; dsegment
   3551     mov  es, ax
   3552     mov  ax, 6[bp] ; doffset
   3553     mov  di, ax
   3554     mov  ax, 8[bp] ; ssegment
   3555     mov  ds, ax
   3556     mov  ax, 10[bp] ; soffset
   3557     mov  si, ax
   3558     cld
   3559     rep
   3560      movsw
   3561 
   3562 memcpyw_end:
   3563     pop si
   3564     pop ds
   3565     pop di
   3566     pop es
   3567     pop cx
   3568     pop ax
   3569 
   3570   pop bp
   3571 ASM_END
   3572 }
   3573 
   3574 /* =========================================================== */
   3575 /*
   3576  * These functions where ripped from Kevin's rombios.c
   3577 */
   3578 /* =========================================================== */
   3579 
   3580 // --------------------------------------------------------------------------------------------
   3581 static Bit8u
   3582 read_byte(seg, offset)
   3583   Bit16u seg;
   3584   Bit16u offset;
   3585 {
   3586 ASM_START
   3587   push bp
   3588   mov  bp, sp
   3589 
   3590     push bx
   3591     push ds
   3592     mov  ax, 4[bp] ; segment
   3593     mov  ds, ax
   3594     mov  bx, 6[bp] ; offset
   3595     mov  al, [bx]
   3596     ;; al = return value (byte)
   3597     pop  ds
   3598     pop  bx
   3599 
   3600   pop  bp
   3601 ASM_END
   3602 }
   3603 
   3604 // --------------------------------------------------------------------------------------------
   3605 static Bit16u
   3606 read_word(seg, offset)
   3607   Bit16u seg;
   3608   Bit16u offset;
   3609 {
   3610 ASM_START
   3611   push bp
   3612   mov  bp, sp
   3613 
   3614     push bx
   3615     push ds
   3616     mov  ax, 4[bp] ; segment
   3617     mov  ds, ax
   3618     mov  bx, 6[bp] ; offset
   3619     mov  ax, [bx]
   3620     ;; ax = return value (word)
   3621     pop  ds
   3622     pop  bx
   3623 
   3624   pop  bp
   3625 ASM_END
   3626 }
   3627 
   3628 // --------------------------------------------------------------------------------------------
   3629 static void
   3630 write_byte(seg, offset, data)
   3631   Bit16u seg;
   3632   Bit16u offset;
   3633   Bit8u  data;
   3634 {
   3635 ASM_START
   3636   push bp
   3637   mov  bp, sp
   3638 
   3639     push ax
   3640     push bx
   3641     push ds
   3642     mov  ax, 4[bp] ; segment
   3643     mov  ds, ax
   3644     mov  bx, 6[bp] ; offset
   3645     mov  al, 8[bp] ; data byte
   3646     mov  [bx], al  ; write data byte
   3647     pop  ds
   3648     pop  bx
   3649     pop  ax
   3650 
   3651   pop  bp
   3652 ASM_END
   3653 }
   3654 
   3655 // --------------------------------------------------------------------------------------------
   3656 static void
   3657 write_word(seg, offset, data)
   3658   Bit16u seg;
   3659   Bit16u offset;
   3660   Bit16u data;
   3661 {
   3662 ASM_START
   3663   push bp
   3664   mov  bp, sp
   3665 
   3666     push ax
   3667     push bx
   3668     push ds
   3669     mov  ax, 4[bp] ; segment
   3670     mov  ds, ax
   3671     mov  bx, 6[bp] ; offset
   3672     mov  ax, 8[bp] ; data word
   3673     mov  [bx], ax  ; write data word
   3674     pop  ds
   3675     pop  bx
   3676     pop  ax
   3677 
   3678   pop  bp
   3679 ASM_END
   3680 }
   3681 
   3682 // --------------------------------------------------------------------------------------------
   3683  Bit8u
   3684 inb(port)
   3685   Bit16u port;
   3686 {
   3687 ASM_START
   3688   push bp
   3689   mov  bp, sp
   3690 
   3691     push dx
   3692     mov  dx, 4[bp]
   3693     in   al, dx
   3694     pop  dx
   3695 
   3696   pop  bp
   3697 ASM_END
   3698 }
   3699 
   3700   Bit16u
   3701 inw(port)
   3702   Bit16u port;
   3703 {
   3704 ASM_START
   3705   push bp
   3706   mov  bp, sp
   3707 
   3708     push dx
   3709     mov  dx, 4[bp]
   3710     in   ax, dx
   3711     pop  dx
   3712 
   3713   pop  bp
   3714 ASM_END
   3715 }
   3716 
   3717 // --------------------------------------------------------------------------------------------
   3718   void
   3719 outb(port, val)
   3720   Bit16u port;
   3721   Bit8u  val;
   3722 {
   3723 ASM_START
   3724   push bp
   3725   mov  bp, sp
   3726 
   3727     push ax
   3728     push dx
   3729     mov  dx, 4[bp]
   3730     mov  al, 6[bp]
   3731     out  dx, al
   3732     pop  dx
   3733     pop  ax
   3734 
   3735   pop  bp
   3736 ASM_END
   3737 }
   3738 
   3739 // --------------------------------------------------------------------------------------------
   3740   void
   3741 outw(port, val)
   3742   Bit16u port;
   3743   Bit16u  val;
   3744 {
   3745 ASM_START
   3746   push bp
   3747   mov  bp, sp
   3748 
   3749     push ax
   3750     push dx
   3751     mov  dx, 4[bp]
   3752     mov  ax, 6[bp]
   3753     out  dx, ax
   3754     pop  dx
   3755     pop  ax
   3756 
   3757   pop  bp
   3758 ASM_END
   3759 }
   3760 
   3761 Bit16u get_SS()
   3762 {
   3763 ASM_START
   3764   mov  ax, ss
   3765 ASM_END
   3766 }
   3767 
   3768 #ifdef DEBUG
   3769 void unimplemented()
   3770 {
   3771  printf("--> Unimplemented\n");
   3772 }
   3773 
   3774 void unknown()
   3775 {
   3776  printf("--> Unknown int10\n");
   3777 }
   3778 #endif
   3779 
   3780 // --------------------------------------------------------------------------------------------
   3781 #if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
   3782 void printf(s)
   3783   Bit8u *s;
   3784 {
   3785   Bit8u c, format_char;
   3786   Boolean  in_format;
   3787   unsigned format_width, i;
   3788   Bit16u  *arg_ptr;
   3789   Bit16u   arg_seg, arg, digit, nibble, shift_count;
   3790 
   3791   arg_ptr = &s;
   3792   arg_seg = get_SS();
   3793 
   3794   in_format = 0;
   3795   format_width = 0;
   3796 
   3797   while (c = read_byte(0xc000, s)) {
   3798     if ( c == '%' ) {
   3799       in_format = 1;
   3800       format_width = 0;
   3801       }
   3802     else if (in_format) {
   3803       if ( (c>='0') && (c<='9') ) {
   3804         format_width = (format_width * 10) + (c - '0');
   3805         }
   3806       else if (c == 'x') {
   3807         arg_ptr++; // increment to next arg
   3808         arg = read_word(arg_seg, arg_ptr);
   3809         if (format_width == 0)
   3810           format_width = 4;
   3811         i = 0;
   3812         digit = format_width - 1;
   3813         for (i=0; i<format_width; i++) {
   3814           nibble = (arg >> (4 * digit)) & 0x000f;
   3815           if (nibble <= 9)
   3816             outb(0x0500, nibble + '0');
   3817           else
   3818             outb(0x0500, (nibble - 10) + 'A');
   3819           digit--;
   3820           }
   3821         in_format = 0;
   3822         }
   3823       //else if (c == 'd') {
   3824       //  in_format = 0;
   3825       //  }
   3826       }
   3827     else {
   3828       outb(0x0500, c);
   3829       }
   3830     s ++;
   3831     }
   3832 }
   3833 #endif
   3834 
   3835 ASM_START
   3836   ; get LFB address from PCI
   3837   ; in - ax: PCI device vendor
   3838   ; out - ax: LFB address (high 16 bit)
   3839   ;; NOTE - may be called in protected mode
   3840 _pci_get_lfb_addr:
   3841   push bx
   3842   push cx
   3843   push dx
   3844   push eax
   3845     mov bx, ax
   3846     xor cx, cx
   3847     mov dl, #0x00
   3848     call pci_read_reg
   3849     cmp ax, #0xffff
   3850     jz pci_get_lfb_addr_5
   3851  pci_get_lfb_addr_3:
   3852     mov dl, #0x00
   3853     call pci_read_reg
   3854     cmp ax, bx ;; check vendor
   3855     jz pci_get_lfb_addr_4
   3856     add cx, #0x8
   3857     cmp cx, #0x200 ;; search bus #0 and #1
   3858     jb pci_get_lfb_addr_3
   3859  pci_get_lfb_addr_5:
   3860     xor dx, dx ;; no LFB
   3861     jmp pci_get_lfb_addr_6
   3862  pci_get_lfb_addr_4:
   3863     mov dl, #0x10 ;; I/O space #0
   3864     call pci_read_reg
   3865     test ax, #0xfff1
   3866     jnz pci_get_lfb_addr_5
   3867     shr eax, #16
   3868     mov dx, ax ;; LFB address
   3869  pci_get_lfb_addr_6:
   3870   pop eax
   3871   mov ax, dx
   3872   pop dx
   3873   pop cx
   3874   pop bx
   3875   ret
   3876 
   3877   ; read PCI register
   3878   ; in - cx: device/function
   3879   ; in - dl: register
   3880   ; out - eax: value
   3881 pci_read_reg:
   3882   mov eax, #0x00800000
   3883   mov ax, cx
   3884   shl eax, #8
   3885   mov al, dl
   3886   mov dx, #0xcf8
   3887   out dx, eax
   3888   add dl, #4
   3889   in  eax, dx
   3890   ret
   3891 ASM_END
   3892 
   3893 #ifdef VBE
   3894 #include "vbe.c"
   3895 #endif
   3896 
   3897 #ifdef CIRRUS
   3898 #include "clext.c"
   3899 #endif
   3900 
   3901 // --------------------------------------------------------------------------------------------
   3902 
   3903 ASM_START
   3904 ;; DATA_SEG_DEFS_HERE
   3905 ASM_END
   3906 
   3907 ASM_START
   3908 .ascii "vgabios ends here"
   3909 .byte  0x00
   3910 vgabios_end:
   3911 .byte 0xCB
   3912 ;; BLOCK_STRINGS_BEGIN
   3913 ASM_END
   3914