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