Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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