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@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 */
60static Bit8u          read_byte();
61static Bit16u         read_word();
62static void           write_byte();
63static void           write_word();
64static Bit8u          inb();
65static Bit16u         inw();
66static void           outb();
67static void           outw();
68
69static Bit16u         get_SS();
70
71// Output
72static void           printf();
73static void           unimplemented();
74static void           unknown();
75
76static Bit8u find_vga_entry();
77
78static void memsetb();
79static void memsetw();
80static void memcpyb();
81static void memcpyw();
82
83static void biosfn_set_video_mode();
84static void biosfn_set_cursor_shape();
85static void biosfn_set_cursor_pos();
86static void biosfn_get_cursor_pos();
87static void biosfn_set_active_page();
88static void biosfn_scroll();
89static void biosfn_read_char_attr();
90static void biosfn_write_char_attr();
91static void biosfn_write_char_only();
92static void biosfn_write_pixel();
93static void biosfn_read_pixel();
94static void biosfn_write_teletype();
95static void biosfn_perform_gray_scale_summing();
96static void biosfn_load_text_user_pat();
97static void biosfn_load_text_8_14_pat();
98static void biosfn_load_text_8_8_pat();
99static void biosfn_load_text_8_16_pat();
100static void biosfn_load_gfx_8_8_chars();
101static void biosfn_load_gfx_user_chars();
102static void biosfn_load_gfx_8_14_chars();
103static void biosfn_load_gfx_8_8_dd_chars();
104static void biosfn_load_gfx_8_16_chars();
105static void biosfn_get_font_info();
106static void biosfn_alternate_prtsc();
107static void biosfn_switch_video_interface();
108static void biosfn_enable_video_refresh_control();
109static void biosfn_write_string();
110static void biosfn_read_state_info();
111static void biosfn_read_video_state_size();
112static Bit16u biosfn_save_video_state();
113static Bit16u biosfn_restore_video_state();
114extern 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
120ASM_START
121
122MACRO 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
131MEND
132
133ASM_END
134
135ASM_START
136.text
137.rom
138.org 0
139
140use16 386
141
142vgabios_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
148vgabios_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
162vgabios_name:
163.ascii	"Plex86/Bochs VGABios"
164#ifdef PCIBIOS
165.ascii	" (PCI)"
166#endif
167.ascii	" "
168.byte	0x00
169
170vgabios_version:
171#ifndef VGABIOS_VERS
172.ascii	"current-cvs"
173#else
174.ascii VGABIOS_VERS
175#endif
176.ascii	" "
177
178vgabios_date:
179.ascii  VGABIOS_DATE
180.byte   0x0a,0x0d
181.byte	0x00
182
183vgabios_copyright:
184.ascii	"(C) 2008 the LGPL VGABios developers Team"
185.byte	0x0a,0x0d
186.byte	0x00
187
188vgabios_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
194vgabios_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
207vgabios_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;; ============================================================================================
233vgabios_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
274ASM_END
275
276/*
277 *  int10 handled here
278 */
279ASM_START
280vgabios_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
297int10_test_1A:
298  cmp   ah, #0x1a
299  jne   int10_test_0B
300  call  biosfn_group_1A
301  jmp   int10_end
302int10_test_0B:
303  cmp   ah, #0x0b
304  jne   int10_test_1103
305  call  biosfn_group_0B
306  jmp   int10_end
307int10_test_1103:
308  cmp   ax, #0x1103
309  jne   int10_test_12
310  call  biosfn_set_text_block_specifier
311  jmp   int10_end
312int10_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
319int10_test_BL30:
320  cmp   bl, #0x30
321  jne   int10_test_BL31
322  call  biosfn_select_vert_res
323  jmp   int10_end
324int10_test_BL31:
325  cmp   bl, #0x31
326  jne   int10_test_BL32
327  call  biosfn_enable_default_palette_loading
328  jmp   int10_end
329int10_test_BL32:
330  cmp   bl, #0x32
331  jne   int10_test_BL33
332  call  biosfn_enable_video_addressing
333  jmp   int10_end
334int10_test_BL33:
335  cmp   bl, #0x33
336  jne   int10_test_BL34
337  call  biosfn_enable_grayscale_summing
338  jmp   int10_end
339int10_test_BL34:
340  cmp   bl, #0x34
341  jne   int10_normal
342  call  biosfn_enable_cursor_emulation
343  jmp   int10_end
344int10_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
356int10_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
363int10_test_vbe_05:
364  cmp   al, #0x05
365  jne   int10_test_vbe_06
366  call  vbe_biosfn_display_window_control
367  jmp   int10_end
368int10_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
373int10_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
378int10_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
383int10_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
390int10_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
403int10_end:
404  popf
405  iret
406ASM_END
407
408#include "vgatables.h"
409#include "vgafonts.h"
410
411/*
412 * Boot time harware inits
413 */
414ASM_START
415init_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)
439msg_vga_init:
440.ascii "VGABios $Id$"
441.byte 0x0d,0x0a,0x00
442#endif
443ASM_END
444
445// --------------------------------------------------------------------------------------------
446/*
447 *  Boot time bios area inits
448 */
449ASM_START
450init_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
515ASM_END
516
517// --------------------------------------------------------------------------------------------
518/*
519 *  Boot time Splash screen
520 */
521static void display_splash_screen()
522{
523}
524
525// --------------------------------------------------------------------------------------------
526/*
527 *  Tell who we are
528 */
529
530static void display_info()
531{
532ASM_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
549ASM_END
550}
551
552static void display_string()
553{
554 // Get length of string
555ASM_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
578ASM_END
579}
580
581// --------------------------------------------------------------------------------------------
582#ifdef DEBUG
583static 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 */
596static 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
826static 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  {
1016ASM_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
1024ASM_END
1025  }
1026
1027 // Set the ints 0x1F and 0x43
1028ASM_START
1029 SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
1030ASM_END
1031
1032  switch(cheight)
1033   {case 8:
1034ASM_START
1035     SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
1036ASM_END
1037     break;
1038    case 14:
1039ASM_START
1040     SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
1041ASM_END
1042     break;
1043    case 16:
1044ASM_START
1045     SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
1046ASM_END
1047     break;
1048   }
1049}
1050
1051// --------------------------------------------------------------------------------------------
1052static void biosfn_set_cursor_shape (CH,CL)
1053Bit8u 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// --------------------------------------------------------------------------------------------
1087static void biosfn_set_cursor_pos (page, cursor)
1088Bit8u 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// --------------------------------------------------------------------------------------------
1122static void biosfn_get_cursor_pos (page,shape, pos)
1123Bit8u 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// --------------------------------------------------------------------------------------------
1138static void biosfn_set_active_page (page)
1139Bit8u 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// --------------------------------------------------------------------------------------------
1192static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
1193Bit8u 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// --------------------------------------------------------------------------------------------
1209static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
1210Bit8u 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// --------------------------------------------------------------------------------------------
1225static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
1226Bit8u 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// --------------------------------------------------------------------------------------------
1243static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
1244Bit8u 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// --------------------------------------------------------------------------------------------
1260static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
1261Bit8u 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// --------------------------------------------------------------------------------------------
1408static void biosfn_read_char_attr (page,car)
1409Bit8u 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// --------------------------------------------------------------------------------------------
1445static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
1446Bit8u 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  }
1492ASM_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
1500ASM_END
1501}
1502
1503// --------------------------------------------------------------------------------------------
1504static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
1505Bit8u 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// --------------------------------------------------------------------------------------------
1581static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
1582Bit8u 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// --------------------------------------------------------------------------------------------
1609static void biosfn_write_char_attr (car,page,attr,count)
1610Bit8u 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// --------------------------------------------------------------------------------------------
1667static void biosfn_write_char_only (car,page,attr,count)
1668Bit8u 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// --------------------------------------------------------------------------------------------
1727ASM_START
1728biosfn_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
1737biosfn_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
1752set_low_border:
1753  out   dx, al
1754  mov   cl, #0x01
1755  and   bl, #0x10
1756set_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
1776biosfn_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
1785set_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
1805ASM_END
1806
1807// --------------------------------------------------------------------------------------------
1808static 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);
1833ASM_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
1841ASM_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// --------------------------------------------------------------------------------------------
1887static 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// --------------------------------------------------------------------------------------------
1940static void biosfn_write_teletype (car, page, attr, flag)
1941Bit8u 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// --------------------------------------------------------------------------------------------
2059ASM_START
2060biosfn_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
2081ASM_END
2082
2083// --------------------------------------------------------------------------------------------
2084ASM_START
2085biosfn_group_10:
2086  cmp   al, #0x00
2087  jne   int10_test_1001
2088  jmp   biosfn_set_single_palette_reg
2089int10_test_1001:
2090  cmp   al, #0x01
2091  jne   int10_test_1002
2092  jmp   biosfn_set_overscan_border_color
2093int10_test_1002:
2094  cmp   al, #0x02
2095  jne   int10_test_1003
2096  jmp   biosfn_set_all_palette_reg
2097int10_test_1003:
2098  cmp   al, #0x03
2099  jne   int10_test_1007
2100  jmp   biosfn_toggle_intensity
2101int10_test_1007:
2102  cmp   al, #0x07
2103  jne   int10_test_1008
2104  jmp   biosfn_get_single_palette_reg
2105int10_test_1008:
2106  cmp   al, #0x08
2107  jne   int10_test_1009
2108  jmp   biosfn_read_overscan_border_color
2109int10_test_1009:
2110  cmp   al, #0x09
2111  jne   int10_test_1010
2112  jmp   biosfn_get_all_palette_reg
2113int10_test_1010:
2114  cmp   al, #0x10
2115  jne   int10_test_1012
2116  jmp  biosfn_set_single_dac_reg
2117int10_test_1012:
2118  cmp   al, #0x12
2119  jne   int10_test_1013
2120  jmp   biosfn_set_all_dac_reg
2121int10_test_1013:
2122  cmp   al, #0x13
2123  jne   int10_test_1015
2124  jmp   biosfn_select_video_dac_color_page
2125int10_test_1015:
2126  cmp   al, #0x15
2127  jne   int10_test_1017
2128  jmp   biosfn_read_single_dac_reg
2129int10_test_1017:
2130  cmp   al, #0x17
2131  jne   int10_test_1018
2132  jmp   biosfn_read_all_dac_reg
2133int10_test_1018:
2134  cmp   al, #0x18
2135  jne   int10_test_1019
2136  jmp   biosfn_set_pel_mask
2137int10_test_1019:
2138  cmp   al, #0x19
2139  jne   int10_test_101A
2140  jmp   biosfn_read_pel_mask
2141int10_test_101A:
2142  cmp   al, #0x1a
2143  jne   int10_group_10_unknown
2144  jmp   biosfn_read_video_dac_state
2145int10_group_10_unknown:
2146#ifdef DEBUG
2147  call  _unknown
2148#endif
2149  ret
2150
2151biosfn_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
2167no_actl_reg1:
2168  ret
2169ASM_END
2170
2171// --------------------------------------------------------------------------------------------
2172ASM_START
2173biosfn_set_overscan_border_color:
2174  push  bx
2175  mov   bl, #0x11
2176  call  biosfn_set_single_palette_reg
2177  pop   bx
2178  ret
2179ASM_END
2180
2181// --------------------------------------------------------------------------------------------
2182ASM_START
2183biosfn_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
2193set_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
2215ASM_END
2216
2217// --------------------------------------------------------------------------------------------
2218ASM_START
2219biosfn_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
2242ASM_END
2243
2244// --------------------------------------------------------------------------------------------
2245ASM_START
2246biosfn_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
2266no_actl_reg2:
2267  ret
2268ASM_END
2269
2270// --------------------------------------------------------------------------------------------
2271ASM_START
2272biosfn_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
2282ASM_END
2283
2284// --------------------------------------------------------------------------------------------
2285ASM_START
2286biosfn_get_all_palette_reg:
2287  push  ax
2288  push  bx
2289  push  cx
2290  push  dx
2291  mov   bx, dx
2292  mov   cl, #0x00
2293get_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
2326ASM_END
2327
2328// --------------------------------------------------------------------------------------------
2329ASM_START
2330biosfn_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
2348ASM_END
2349
2350// --------------------------------------------------------------------------------------------
2351ASM_START
2352biosfn_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
2364set_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
2384ASM_END
2385
2386// --------------------------------------------------------------------------------------------
2387ASM_START
2388biosfn_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
2407set_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
2418set_dac_16_page:
2419  and   bh, #0x0f
2420  mov   al, bh
2421  out   dx, al
2422set_actl_normal:
2423  mov   al, #0x20
2424  out   dx, al
2425  pop   dx
2426  pop   bx
2427  pop   ax
2428  ret
2429ASM_END
2430
2431// --------------------------------------------------------------------------------------------
2432ASM_START
2433biosfn_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
2452ASM_END
2453
2454// --------------------------------------------------------------------------------------------
2455ASM_START
2456biosfn_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
2468read_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
2488ASM_END
2489
2490// --------------------------------------------------------------------------------------------
2491ASM_START
2492biosfn_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
2501ASM_END
2502
2503// --------------------------------------------------------------------------------------------
2504ASM_START
2505biosfn_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
2514ASM_END
2515
2516// --------------------------------------------------------------------------------------------
2517ASM_START
2518biosfn_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
2542get_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
2551ASM_END
2552
2553// --------------------------------------------------------------------------------------------
2554static void biosfn_perform_gray_scale_summing (start,count)
2555Bit16u 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// --------------------------------------------------------------------------------------------
2590static void get_font_access()
2591{
2592ASM_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
2609ASM_END
2610}
2611
2612static void release_font_access()
2613{
2614ASM_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
2637ASM_END
2638}
2639
2640ASM_START
2641idiv_u:
2642  xor dx,dx
2643  div bx
2644  ret
2645ASM_END
2646
2647static 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
2677static 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
2696static 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
2715static 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// --------------------------------------------------------------------------------------------
2735ASM_START
2736biosfn_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
2746ASM_END
2747
2748// --------------------------------------------------------------------------------------------
2749static 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
2768static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
2769{
2770#ifdef DEBUG
2771 unimplemented();
2772#endif
2773}
2774static 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}
2780static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
2781{
2782#ifdef DEBUG
2783 unimplemented();
2784#endif
2785}
2786static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
2787{
2788#ifdef DEBUG
2789 unimplemented();
2790#endif
2791}
2792static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
2793{
2794#ifdef DEBUG
2795 unimplemented();
2796#endif
2797}
2798// --------------------------------------------------------------------------------------------
2799static void biosfn_get_font_info (BH,ES,BP,CX,DX)
2800Bit8u 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// --------------------------------------------------------------------------------------------
2850ASM_START
2851biosfn_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
2866mode_ega_color:
2867  pop   ax
2868  pop   ds
2869  ret
2870ASM_END
2871
2872// --------------------------------------------------------------------------------------------
2873static void biosfn_alternate_prtsc()
2874{
2875#ifdef DEBUG
2876 unimplemented();
2877#endif
2878}
2879
2880// --------------------------------------------------------------------------------------------
2881ASM_START
2882biosfn_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
2911vert_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
2921vert_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
2930vert_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
2939set_vert_res:
2940  mov   bx, # BIOSMEM_MODESET_CTL
2941  mov   [bx], al
2942  mov   bx, # BIOSMEM_SWITCHES
2943  mov   [bx], ah
2944set_retcode:
2945  mov   ax, #0x1212
2946  pop   dx
2947  pop   bx
2948  pop   ds
2949  ret
2950
2951#ifdef DEBUG
2952msg_vert_res:
2953.ascii "Select vert res (%02x) was discarded"
2954.byte 0x0d,0x0a,0x00
2955#endif
2956
2957
2958biosfn_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
2979biosfn_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
2998biosfn_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
3020biosfn_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
3039ASM_END
3040
3041// --------------------------------------------------------------------------------------------
3042static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
3043{
3044#ifdef DEBUG
3045 unimplemented();
3046#endif
3047}
3048static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
3049{
3050#ifdef DEBUG
3051 unimplemented();
3052#endif
3053}
3054
3055// --------------------------------------------------------------------------------------------
3056static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset)
3057Bit8u 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// --------------------------------------------------------------------------------------------
3089ASM_START
3090biosfn_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
3099biosfn_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
3112biosfn_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
3137msg_alt_dcc:
3138.ascii "Alternate Display code (%02x) was discarded"
3139.byte 0x0d,0x0a,0x00
3140#endif
3141ASM_END
3142
3143// --------------------------------------------------------------------------------------------
3144static void biosfn_read_state_info (BX,ES,DI)
3145Bit16u 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// --------------------------------------------------------------------------------------------
3171static 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
3188static 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
3195static 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
3280static 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// --------------------------------------------------------------------------------------------
3388static Bit8u find_vga_entry(mode)
3389Bit8u 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// --------------------------------------------------------------------------------------------
3407static void memsetb(seg,offset,value,count)
3408  Bit16u seg;
3409  Bit16u offset;
3410  Bit16u value;
3411  Bit16u count;
3412{
3413ASM_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
3434memsetb_end:
3435    pop di
3436    pop es
3437    pop cx
3438    pop ax
3439
3440  pop bp
3441ASM_END
3442}
3443
3444// --------------------------------------------------------------------------------------------
3445static void memsetw(seg,offset,value,count)
3446  Bit16u seg;
3447  Bit16u offset;
3448  Bit16u value;
3449  Bit16u count;
3450{
3451ASM_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
3472memsetw_end:
3473    pop di
3474    pop es
3475    pop cx
3476    pop ax
3477
3478  pop bp
3479ASM_END
3480}
3481
3482// --------------------------------------------------------------------------------------------
3483static void memcpyb(dseg,doffset,sseg,soffset,count)
3484  Bit16u dseg;
3485  Bit16u doffset;
3486  Bit16u sseg;
3487  Bit16u soffset;
3488  Bit16u count;
3489{
3490ASM_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
3516memcpyb_end:
3517    pop si
3518    pop ds
3519    pop di
3520    pop es
3521    pop cx
3522    pop ax
3523
3524  pop bp
3525ASM_END
3526}
3527
3528// --------------------------------------------------------------------------------------------
3529static void memcpyw(dseg,doffset,sseg,soffset,count)
3530  Bit16u dseg;
3531  Bit16u doffset;
3532  Bit16u sseg;
3533  Bit16u soffset;
3534  Bit16u count;
3535{
3536ASM_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
3562memcpyw_end:
3563    pop si
3564    pop ds
3565    pop di
3566    pop es
3567    pop cx
3568    pop ax
3569
3570  pop bp
3571ASM_END
3572}
3573
3574/* =========================================================== */
3575/*
3576 * These functions where ripped from Kevin's rombios.c
3577*/
3578/* =========================================================== */
3579
3580// --------------------------------------------------------------------------------------------
3581static Bit8u
3582read_byte(seg, offset)
3583  Bit16u seg;
3584  Bit16u offset;
3585{
3586ASM_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
3601ASM_END
3602}
3603
3604// --------------------------------------------------------------------------------------------
3605static Bit16u
3606read_word(seg, offset)
3607  Bit16u seg;
3608  Bit16u offset;
3609{
3610ASM_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
3625ASM_END
3626}
3627
3628// --------------------------------------------------------------------------------------------
3629static void
3630write_byte(seg, offset, data)
3631  Bit16u seg;
3632  Bit16u offset;
3633  Bit8u  data;
3634{
3635ASM_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
3652ASM_END
3653}
3654
3655// --------------------------------------------------------------------------------------------
3656static void
3657write_word(seg, offset, data)
3658  Bit16u seg;
3659  Bit16u offset;
3660  Bit16u data;
3661{
3662ASM_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
3679ASM_END
3680}
3681
3682// --------------------------------------------------------------------------------------------
3683 Bit8u
3684inb(port)
3685  Bit16u port;
3686{
3687ASM_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
3697ASM_END
3698}
3699
3700  Bit16u
3701inw(port)
3702  Bit16u port;
3703{
3704ASM_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
3714ASM_END
3715}
3716
3717// --------------------------------------------------------------------------------------------
3718  void
3719outb(port, val)
3720  Bit16u port;
3721  Bit8u  val;
3722{
3723ASM_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
3736ASM_END
3737}
3738
3739// --------------------------------------------------------------------------------------------
3740  void
3741outw(port, val)
3742  Bit16u port;
3743  Bit16u  val;
3744{
3745ASM_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
3758ASM_END
3759}
3760
3761Bit16u get_SS()
3762{
3763ASM_START
3764  mov  ax, ss
3765ASM_END
3766}
3767
3768#ifdef DEBUG
3769void unimplemented()
3770{
3771 printf("--> Unimplemented\n");
3772}
3773
3774void unknown()
3775{
3776 printf("--> Unknown int10\n");
3777}
3778#endif
3779
3780// --------------------------------------------------------------------------------------------
3781#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
3782void 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
3835ASM_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
3881pci_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
3891ASM_END
3892
3893#ifdef VBE
3894#include "vbe.c"
3895#endif
3896
3897#ifdef CIRRUS
3898#include "clext.c"
3899#endif
3900
3901// --------------------------------------------------------------------------------------------
3902
3903ASM_START
3904;; DATA_SEG_DEFS_HERE
3905ASM_END
3906
3907ASM_START
3908.ascii "vgabios ends here"
3909.byte  0x00
3910vgabios_end:
3911.byte 0xCB
3912;; BLOCK_STRINGS_BEGIN
3913ASM_END
3914