32bf71e88a1a492a24aa3f7cd7b8ab13693a18aa
[seabios.git] / vgasrc / vga.c
1 // VGA bios implementation
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8
9 // TODO:
10 //  * introduce "struct vregs", or add ebp to struct bregs.
11 //  * Integrate vga_modes/pallete?/line_to_vpti/dac_regs/video_param_table
12 //  * define structs for save/restore state
13 //  * review correctness of converted asm by comparing with RBIL
14 //  * more syntax cleanups
15 //  * refactor redundant code into sub-functions
16 //  * See if there is a method to the in/out stuff that can be encapsulated.
17 //  * remove "biosfn" prefixes
18 //  * don't hardcode 0xc000
19 //  * add defs for 0xa000/0xb800
20 //  * verify all funcs static
21 //
22 //  * convert vbe/clext code
23 //
24 //  * separate code into separate files
25 //  * extract hw code from bios interfaces
26
27 #include "bregs.h" // struct bregs
28 #include "biosvar.h" // GET_BDA
29 #include "util.h" // memset
30 #include "vgatables.h" // vga_modes
31
32 // XXX
33 #define CONFIG_VBE 0
34 #define CONFIG_CIRRUS 0
35
36 // XXX
37 #define DEBUG_VGA_POST 1
38 #define DEBUG_VGA_10 3
39
40 #define SET_VGA(var, val) SET_FARVAR(0xc000, (var), (val))
41
42
43 // ===================================================================
44 //
45 // Video Utils
46 //
47 // ===================================================================
48
49 // -------------------------------------------------------------------
50 static u8
51 find_vga_entry(u8 mode)
52 {
53     u8 i;
54     for (i = 0; i <= MODE_MAX; i++)
55         if (GET_GLOBAL(vga_modes[i].svgamode) == mode)
56             return i;
57     return 0xFF;
58 }
59
60 inline void
61 call16_vgaint(u32 eax, u32 ebx)
62 {
63     asm volatile(
64         "int $0x10\n"
65         "cli\n"
66         "cld"
67         :
68         : "a"(eax), "b"(ebx)
69         : "cc", "memory");
70 }
71
72 // XXX
73 inline void
74 memcpy16_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
75 {
76     memcpy_far(d_seg, d_far, s_seg, s_far, len);
77 }
78
79
80 // ===================================================================
81 //
82 // BIOS functions
83 //
84 // ===================================================================
85
86 // -------------------------------------------------------------------
87 static void
88 biosfn_perform_gray_scale_summing(u16 start, u16 count)
89 {
90     u8 r, g, b;
91     u16 i;
92     u16 index;
93
94     inb(VGAREG_ACTL_RESET);
95     outb(0x00, VGAREG_ACTL_ADDRESS);
96
97     for (index = 0; index < count; index++) {
98         // set read address and switch to read mode
99         outb(start, VGAREG_DAC_READ_ADDRESS);
100         // get 6-bit wide RGB data values
101         r = inb(VGAREG_DAC_DATA);
102         g = inb(VGAREG_DAC_DATA);
103         b = inb(VGAREG_DAC_DATA);
104
105         // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
106         i = ((77 * r + 151 * g + 28 * b) + 0x80) >> 8;
107
108         if (i > 0x3f)
109             i = 0x3f;
110
111         // set write address and switch to write mode
112         outb(start, VGAREG_DAC_WRITE_ADDRESS);
113         // write new intensity value
114         outb(i & 0xff, VGAREG_DAC_DATA);
115         outb(i & 0xff, VGAREG_DAC_DATA);
116         outb(i & 0xff, VGAREG_DAC_DATA);
117         start++;
118     }
119     inb(VGAREG_ACTL_RESET);
120     outb(0x20, VGAREG_ACTL_ADDRESS);
121 }
122
123 // -------------------------------------------------------------------
124 static void
125 biosfn_set_cursor_shape(u8 CH, u8 CL)
126 {
127     u16 cheight, curs, crtc_addr;
128     u8 modeset_ctl;
129
130     CH &= 0x3f;
131     CL &= 0x1f;
132
133     curs = (CH << 8) + CL;
134     SET_BDA(cursor_type, curs);
135
136     modeset_ctl = GET_BDA(modeset_ctl);
137     cheight = GET_BDA(char_height);
138     if ((modeset_ctl & 0x01) && (cheight > 8) && (CL < 8) && (CH < 0x20)) {
139         if (CL != (CH + 1)) {
140             CH = ((CH + 1) * cheight / 8) - 1;
141         } else {
142             CH = ((CL + 1) * cheight / 8) - 2;
143         }
144         CL = ((CL + 1) * cheight / 8) - 1;
145     }
146     // CTRC regs 0x0a and 0x0b
147     crtc_addr = GET_BDA(crtc_address);
148     outb(0x0a, crtc_addr);
149     outb(CH, crtc_addr + 1);
150     outb(0x0b, crtc_addr);
151     outb(CL, crtc_addr + 1);
152 }
153
154 // -------------------------------------------------------------------
155 static void
156 biosfn_set_cursor_pos(u8 page, u16 cursor)
157 {
158     u8 xcurs, ycurs, current;
159     u16 nbcols, nbrows, address, crtc_addr;
160
161     // Should not happen...
162     if (page > 7)
163         return;
164
165     // Bios cursor pos
166     SET_BDA(cursor_pos[page], cursor);
167
168     // Set the hardware cursor
169     current = GET_BDA(video_page);
170     if (page == current) {
171         // Get the dimensions
172         nbcols = GET_BDA(video_cols);
173         nbrows = GET_BDA(video_rows) + 1;
174
175         xcurs = cursor & 0x00ff;
176         ycurs = (cursor & 0xff00) >> 8;
177
178         // Calculate the address knowing nbcols nbrows and page num
179         address =
180             SCREEN_IO_START(nbcols, nbrows, page) + xcurs + ycurs * nbcols;
181
182         // CRTC regs 0x0e and 0x0f
183         crtc_addr = GET_BDA(crtc_address);
184         outb(0x0e, crtc_addr);
185         outb((address & 0xff00) >> 8, crtc_addr + 1);
186         outb(0x0f, crtc_addr);
187         outb(address & 0x00ff, crtc_addr + 1);
188     }
189 }
190
191 // -------------------------------------------------------------------
192 static void
193 biosfn_get_cursor_pos(u8 page, u16 *shape, u16 *pos)
194 {
195     // Default
196     *shape = 0;
197     *pos = 0;
198     if (page > 7)
199         return;
200
201     // FIXME should handle VGA 14/16 lines
202     *shape = GET_BDA(cursor_type);
203     *pos = GET_BDA(cursor_pos[page]);
204 }
205
206 // -------------------------------------------------------------------
207 static void
208 biosfn_set_active_page(u8 page)
209 {
210     u16 cursor, dummy, crtc_addr;
211     u16 nbcols, nbrows, address;
212     u8 mode, line;
213
214     if (page > 7)
215         return;
216
217     // Get the mode
218     mode = GET_BDA(video_mode);
219     line = find_vga_entry(mode);
220     if (line == 0xFF)
221         return;
222
223     // Get pos curs pos for the right page
224     biosfn_get_cursor_pos(page, &dummy, &cursor);
225
226     if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
227         // Get the dimensions
228         nbcols = GET_BDA(video_cols);
229         nbrows = GET_BDA(video_rows) + 1;
230
231         // Calculate the address knowing nbcols nbrows and page num
232         address = SCREEN_MEM_START(nbcols, nbrows, page);
233         SET_BDA(video_pagestart, address);
234
235         // Start address
236         address = SCREEN_IO_START(nbcols, nbrows, page);
237     } else {
238         address = page * GET_GLOBAL(video_param_table[GET_GLOBAL(line_to_vpti[line])].slength);
239     }
240
241     // CRTC regs 0x0c and 0x0d
242     crtc_addr = GET_BDA(crtc_address);
243     outb(0x0c, crtc_addr);
244     outb((address & 0xff00) >> 8, crtc_addr + 1);
245     outb(0x0d, crtc_addr);
246     outb(address & 0x00ff, crtc_addr + 1);
247
248     // And change the BIOS page
249     SET_BDA(video_page, page);
250
251     dprintf(1, "Set active page %02x address %04x\n", page, address);
252
253     // Display the cursor, now the page is active
254     biosfn_set_cursor_pos(page, cursor);
255 }
256
257 static void
258 biosfn_set_video_mode(u8 mode)
259 {                               // mode: Bit 7 is 1 if no clear screen
260     // Should we clear the screen ?
261     u8 noclearmem = mode & 0x80;
262     u8 line, mmask, *palette, vpti;
263     u16 i, twidth, theightm1, cheight;
264     u8 modeset_ctl, video_ctl, vga_switches;
265
266     if (CONFIG_CIRRUS)
267         cirrus_set_video_mode(mode);
268
269 #ifdef VBE
270     if (vbe_has_vbe_display())
271         dispi_set_enable(VBE_DISPI_DISABLED);
272 #endif
273
274     // The real mode
275     mode = mode & 0x7f;
276
277     // find the entry in the video modes
278     line = find_vga_entry(mode);
279
280     dprintf(1, "mode search %02x found line %02x\n", mode, line);
281
282     if (line == 0xFF)
283         return;
284
285     vpti = GET_GLOBAL(line_to_vpti[line]);
286     twidth = GET_GLOBAL(video_param_table[vpti].twidth);
287     theightm1 = GET_GLOBAL(video_param_table[vpti].theightm1);
288     cheight = GET_GLOBAL(video_param_table[vpti].cheight);
289
290     // Read the bios vga control
291     video_ctl = GET_BDA(video_ctl);
292
293     // Read the bios vga switches
294     vga_switches = GET_BDA(video_switches);
295
296     // Read the bios mode set control
297     modeset_ctl = GET_BDA(modeset_ctl);
298
299     // Then we know the number of lines
300 // FIXME
301
302     // if palette loading (bit 3 of modeset ctl = 0)
303     if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
304         outb(GET_GLOBAL(vga_modes[line].pelmask), VGAREG_PEL_MASK);
305
306         // Set the whole dac always, from 0
307         outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
308
309         // From which palette
310         switch (GET_GLOBAL(vga_modes[line].dacmodel)) {
311         default:
312         case 0:
313             palette = palette0;
314             break;
315         case 1:
316             palette = palette1;
317             break;
318         case 2:
319             palette = palette2;
320             break;
321         case 3:
322             palette = palette3;
323             break;
324         }
325         // Always 256*3 values
326         for (i = 0; i < 0x0100; i++) {
327             if (i <= GET_GLOBAL(dac_regs[GET_GLOBAL(vga_modes[line].dacmodel)])) {
328                 outb(GET_GLOBAL(palette[(i * 3) + 0]), VGAREG_DAC_DATA);
329                 outb(GET_GLOBAL(palette[(i * 3) + 1]), VGAREG_DAC_DATA);
330                 outb(GET_GLOBAL(palette[(i * 3) + 2]), VGAREG_DAC_DATA);
331             } else {
332                 outb(0, VGAREG_DAC_DATA);
333                 outb(0, VGAREG_DAC_DATA);
334                 outb(0, VGAREG_DAC_DATA);
335             }
336         }
337         if ((modeset_ctl & 0x02) == 0x02)
338             biosfn_perform_gray_scale_summing(0x00, 0x100);
339     }
340     // Reset Attribute Ctl flip-flop
341     inb(VGAREG_ACTL_RESET);
342
343     // Set Attribute Ctl
344     for (i = 0; i <= 0x13; i++) {
345         outb(i, VGAREG_ACTL_ADDRESS);
346         outb(GET_GLOBAL(video_param_table[vpti].actl_regs[i])
347              , VGAREG_ACTL_WRITE_DATA);
348     }
349     outb(0x14, VGAREG_ACTL_ADDRESS);
350     outb(0x00, VGAREG_ACTL_WRITE_DATA);
351
352     // Set Sequencer Ctl
353     outb(0, VGAREG_SEQU_ADDRESS);
354     outb(0x03, VGAREG_SEQU_DATA);
355     for (i = 1; i <= 4; i++) {
356         outb(i, VGAREG_SEQU_ADDRESS);
357         outb(GET_GLOBAL(video_param_table[vpti].sequ_regs[i - 1])
358              , VGAREG_SEQU_DATA);
359     }
360
361     // Set Grafx Ctl
362     for (i = 0; i <= 8; i++) {
363         outb(i, VGAREG_GRDC_ADDRESS);
364         outb(GET_GLOBAL(video_param_table[vpti].grdc_regs[i])
365              , VGAREG_GRDC_DATA);
366     }
367
368     // Set CRTC address VGA or MDA
369     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
370     if (GET_GLOBAL(vga_modes[line].memmodel) == MTEXT)
371         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
372
373     // Disable CRTC write protection
374     outw(0x0011, crtc_addr);
375     // Set CRTC regs
376     for (i = 0; i <= 0x18; i++) {
377         outb(i, crtc_addr);
378         outb(GET_GLOBAL(video_param_table[vpti].crtc_regs[i]), crtc_addr + 1);
379     }
380
381     // Set the misc register
382     outb(GET_GLOBAL(video_param_table[vpti].miscreg), VGAREG_WRITE_MISC_OUTPUT);
383
384     // Enable video
385     outb(0x20, VGAREG_ACTL_ADDRESS);
386     inb(VGAREG_ACTL_RESET);
387
388     if (noclearmem == 0x00) {
389         if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
390             memset16_far(GET_GLOBAL(vga_modes[line].sstart)
391                          , 0, 0x0720, 32*1024);
392         } else {
393             if (mode < 0x0d) {
394                 memset16_far(GET_GLOBAL(vga_modes[line].sstart)
395                              , 0, 0x0000, 32*1024);
396             } else {
397                 outb(0x02, VGAREG_SEQU_ADDRESS);
398                 mmask = inb(VGAREG_SEQU_DATA);
399                 outb(0x0f, VGAREG_SEQU_DATA);   // all planes
400                 memset16_far(GET_GLOBAL(vga_modes[line].sstart)
401                              , 0, 0x0000, 64*1024);
402                 outb(mmask, VGAREG_SEQU_DATA);
403             }
404         }
405     }
406     // Set the BIOS mem
407     SET_BDA(video_mode, mode);
408     SET_BDA(video_cols, twidth);
409     SET_BDA(video_pagesize, GET_GLOBAL(video_param_table[vpti].slength));
410     SET_BDA(crtc_address, crtc_addr);
411     SET_BDA(video_rows, theightm1);
412     SET_BDA(char_height, cheight);
413     SET_BDA(video_ctl, (0x60 | noclearmem));
414     SET_BDA(video_switches, 0xF9);
415     SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
416
417     // FIXME We nearly have the good tables. to be reworked
418     SET_BDA(dcc_index, 0x08);   // 8 is VGA should be ok for now
419     SET_BDA(video_savetable_ptr, (u32)video_save_pointer_table);
420     SET_BDA(video_savetable_seg, 0xc000);
421
422     // FIXME
423     SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
424     SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
425
426     // Set cursor shape
427     if (GET_GLOBAL(vga_modes[line].class) == TEXT)
428         biosfn_set_cursor_shape(0x06, 0x07);
429     // Set cursor pos for page 0..7
430     for (i = 0; i < 8; i++)
431         biosfn_set_cursor_pos(i, 0x0000);
432
433     // Set active page 0
434     biosfn_set_active_page(0x00);
435
436     // Write the fonts in memory
437     if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
438         call16_vgaint(0x1104, 0);
439         call16_vgaint(0x1103, 0);
440     }
441     // Set the ints 0x1F and 0x43
442     SET_IVT(0x1f, 0xC000, (u32)&vgafont8[128 * 8]);
443
444     switch (cheight) {
445     case 8:
446         SET_IVT(0x43, 0xC000, (u32)vgafont8);
447         break;
448     case 14:
449         SET_IVT(0x43, 0xC000, (u32)vgafont14);
450         break;
451     case 16:
452         SET_IVT(0x43, 0xC000, (u32)vgafont16);
453         break;
454     }
455 }
456
457 // -------------------------------------------------------------------
458 static void
459 vgamem_copy_pl4(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
460                 u8 cheight)
461 {
462     u16 src = ysrc * cheight * nbcols + xstart;
463     u16 dest = ydest * cheight * nbcols + xstart;
464     outw(0x0105, VGAREG_GRDC_ADDRESS);
465     u8 i;
466     for (i = 0; i < cheight; i++)
467         memcpy_far(0xa000, (void*)(dest + i * nbcols)
468                    , 0xa000, (void*)(src + i * nbcols), cols);
469     outw(0x0005, VGAREG_GRDC_ADDRESS);
470 }
471
472 // -------------------------------------------------------------------
473 static void
474 vgamem_fill_pl4(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
475                 u8 attr)
476 {
477     u16 dest = ystart * cheight * nbcols + xstart;
478     outw(0x0205, VGAREG_GRDC_ADDRESS);
479     u8 i;
480     for (i = 0; i < cheight; i++)
481         memset_far(0xa000, (void*)(dest + i * nbcols), attr, cols);
482     outw(0x0005, VGAREG_GRDC_ADDRESS);
483 }
484
485 // -------------------------------------------------------------------
486 static void
487 vgamem_copy_cga(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
488                 u8 cheight)
489 {
490     u16 src = ((ysrc * cheight * nbcols) >> 1) + xstart;
491     u16 dest = ((ydest * cheight * nbcols) >> 1) + xstart;
492     u8 i;
493     for (i = 0; i < cheight; i++)
494         if (i & 1)
495             memcpy_far(0xb800, (void*)(0x2000 + dest + (i >> 1) * nbcols)
496                        , 0xb800, (void*)(0x2000 + src + (i >> 1) * nbcols)
497                        , cols);
498         else
499             memcpy_far(0xb800, (void*)(dest + (i >> 1) * nbcols)
500                        , 0xb800, (void*)(src + (i >> 1) * nbcols), cols);
501 }
502
503 // -------------------------------------------------------------------
504 static void
505 vgamem_fill_cga(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
506                 u8 attr)
507 {
508     u16 dest = ((ystart * cheight * nbcols) >> 1) + xstart;
509     u8 i;
510     for (i = 0; i < cheight; i++)
511         if (i & 1)
512             memset_far(0xb800, (void*)(0x2000 + dest + (i >> 1) * nbcols)
513                        , attr, cols);
514         else
515             memset_far(0xb800, (void*)(dest + (i >> 1) * nbcols), attr, cols);
516 }
517
518 // -------------------------------------------------------------------
519 static void
520 biosfn_scroll(u8 nblines, u8 attr, u8 rul, u8 cul, u8 rlr, u8 clr, u8 page,
521               u8 dir)
522 {
523     // page == 0xFF if current
524
525     u8 mode, line, cheight, bpp, cols;
526     u16 nbcols, nbrows, i;
527
528     if (rul > rlr)
529         return;
530     if (cul > clr)
531         return;
532
533     // Get the mode
534     mode = GET_BDA(video_mode);
535     line = find_vga_entry(mode);
536     if (line == 0xFF)
537         return;
538
539     // Get the dimensions
540     nbrows = GET_BDA(video_rows) + 1;
541     nbcols = GET_BDA(video_cols);
542
543     // Get the current page
544     if (page == 0xFF)
545         page = GET_BDA(video_page);
546
547     if (rlr >= nbrows)
548         rlr = nbrows - 1;
549     if (clr >= nbcols)
550         clr = nbcols - 1;
551     if (nblines > nbrows)
552         nblines = 0;
553     cols = clr - cul + 1;
554
555     if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
556         // Compute the address
557         void *address = (void*)(SCREEN_MEM_START(nbcols, nbrows, page));
558         dprintf(3, "Scroll, address %p (%d %d %02x)\n"
559                 , address, nbrows, nbcols, page);
560
561         if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
562             && clr == nbcols - 1) {
563             memset16_far(GET_GLOBAL(vga_modes[line].sstart), address
564                          , (u16)attr * 0x100 + ' ', nbrows * nbcols * 2);
565         } else {                // if Scroll up
566             if (dir == SCROLL_UP) {
567                 for (i = rul; i <= rlr; i++) {
568                     if ((i + nblines > rlr) || (nblines == 0))
569                         memset16_far(GET_GLOBAL(vga_modes[line].sstart)
570                                      , address + (i * nbcols + cul) * 2
571                                      , (u16)attr * 0x100 + ' ', cols * 2);
572                     else
573                         memcpy16_far(GET_GLOBAL(vga_modes[line].sstart)
574                                      , address + (i * nbcols + cul) * 2
575                                      , GET_GLOBAL(vga_modes[line].sstart)
576                                      , (void*)(((i + nblines) * nbcols + cul) * 2)
577                                      , cols * 2);
578                 }
579             } else {
580                 for (i = rlr; i >= rul; i--) {
581                     if ((i < rul + nblines) || (nblines == 0))
582                         memset16_far(GET_GLOBAL(vga_modes[line].sstart)
583                                      , address + (i * nbcols + cul) * 2
584                                      , (u16)attr * 0x100 + ' ', cols * 2);
585                     else
586                         memcpy16_far(GET_GLOBAL(vga_modes[line].sstart)
587                                      , address + (i * nbcols + cul) * 2
588                                      , GET_GLOBAL(vga_modes[line].sstart)
589                                      , (void*)(((i - nblines) * nbcols + cul) * 2)
590                                      , cols * 2);
591                     if (i > rlr)
592                         break;
593                 }
594             }
595         }
596     } else {
597         // FIXME gfx mode not complete
598         cheight = GET_GLOBAL(video_param_table[GET_GLOBAL(line_to_vpti[line])].cheight);
599         switch (GET_GLOBAL(vga_modes[line].memmodel)) {
600         case PLANAR4:
601         case PLANAR1:
602             if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
603                 && clr == nbcols - 1) {
604                 outw(0x0205, VGAREG_GRDC_ADDRESS);
605                 memset_far(GET_GLOBAL(vga_modes[line].sstart), 0, attr,
606                            nbrows * nbcols * cheight);
607                 outw(0x0005, VGAREG_GRDC_ADDRESS);
608             } else {            // if Scroll up
609                 if (dir == SCROLL_UP) {
610                     for (i = rul; i <= rlr; i++) {
611                         if ((i + nblines > rlr) || (nblines == 0))
612                             vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
613                                             attr);
614                         else
615                             vgamem_copy_pl4(cul, i + nblines, i, cols,
616                                             nbcols, cheight);
617                     }
618                 } else {
619                     for (i = rlr; i >= rul; i--) {
620                         if ((i < rul + nblines) || (nblines == 0))
621                             vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
622                                             attr);
623                         else
624                             vgamem_copy_pl4(cul, i, i - nblines, cols,
625                                             nbcols, cheight);
626                         if (i > rlr)
627                             break;
628                     }
629                 }
630             }
631             break;
632         case CGA:
633             bpp = GET_GLOBAL(vga_modes[line].pixbits);
634             if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
635                 && clr == nbcols - 1) {
636                 memset_far(GET_GLOBAL(vga_modes[line].sstart), 0, attr,
637                            nbrows * nbcols * cheight * bpp);
638             } else {
639                 if (bpp == 2) {
640                     cul <<= 1;
641                     cols <<= 1;
642                     nbcols <<= 1;
643                 }
644                 // if Scroll up
645                 if (dir == SCROLL_UP) {
646                     for (i = rul; i <= rlr; i++) {
647                         if ((i + nblines > rlr) || (nblines == 0))
648                             vgamem_fill_cga(cul, i, cols, nbcols, cheight,
649                                             attr);
650                         else
651                             vgamem_copy_cga(cul, i + nblines, i, cols,
652                                             nbcols, cheight);
653                     }
654                 } else {
655                     for (i = rlr; i >= rul; i--) {
656                         if ((i < rul + nblines) || (nblines == 0))
657                             vgamem_fill_cga(cul, i, cols, nbcols, cheight,
658                                             attr);
659                         else
660                             vgamem_copy_cga(cul, i, i - nblines, cols,
661                                             nbcols, cheight);
662                         if (i > rlr)
663                             break;
664                     }
665                 }
666             }
667             break;
668         default:
669             dprintf(1, "Scroll in graphics mode\n");
670         }
671     }
672 }
673
674 // -------------------------------------------------------------------
675 static void
676 biosfn_read_char_attr(u8 page, u16 *car)
677 {
678     u8 xcurs, ycurs, mode, line;
679     u16 nbcols, nbrows;
680     u16 cursor, dummy;
681
682     // Get the mode
683     mode = GET_BDA(video_mode);
684     line = find_vga_entry(mode);
685     if (line == 0xFF)
686         return;
687
688     // Get the cursor pos for the page
689     biosfn_get_cursor_pos(page, &dummy, &cursor);
690     xcurs = cursor & 0x00ff;
691     ycurs = (cursor & 0xff00) >> 8;
692
693     // Get the dimensions
694     nbrows = GET_BDA(video_rows) + 1;
695     nbcols = GET_BDA(video_cols);
696
697     if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
698         // Compute the address
699         u16 *address = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
700                                + (xcurs + ycurs * nbcols) * 2);
701
702         *car = GET_FARVAR(GET_GLOBAL(vga_modes[line].sstart), *address);
703     } else {
704         // FIXME gfx mode
705         dprintf(1, "Read char in graphics mode\n");
706     }
707 }
708
709 // -------------------------------------------------------------------
710 static void
711 write_gfx_char_pl4(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols,
712                    u8 cheight)
713 {
714     u8 i, j, mask;
715     u8 *fdata;
716     u16 addr, src;
717
718     switch (cheight) {
719     case 14:
720         fdata = vgafont14;
721         break;
722     case 16:
723         fdata = vgafont16;
724         break;
725     default:
726         fdata = vgafont8;
727     }
728     addr = xcurs + ycurs * cheight * nbcols;
729     src = car * cheight;
730     outw(0x0f02, VGAREG_SEQU_ADDRESS);
731     outw(0x0205, VGAREG_GRDC_ADDRESS);
732     if (attr & 0x80)
733         outw(0x1803, VGAREG_GRDC_ADDRESS);
734     else
735         outw(0x0003, VGAREG_GRDC_ADDRESS);
736     for (i = 0; i < cheight; i++) {
737         u8 *dest = (void*)(addr + i * nbcols);
738         for (j = 0; j < 8; j++) {
739             mask = 0x80 >> j;
740             outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
741             GET_FARVAR(0xa000, *dest);
742             if (GET_GLOBAL(fdata[src + i]) & mask)
743                 SET_FARVAR(0xa000, *dest, attr & 0x0f);
744             else
745                 SET_FARVAR(0xa000, *dest, 0x00);
746         }
747     }
748     outw(0xff08, VGAREG_GRDC_ADDRESS);
749     outw(0x0005, VGAREG_GRDC_ADDRESS);
750     outw(0x0003, VGAREG_GRDC_ADDRESS);
751 }
752
753 // -------------------------------------------------------------------
754 static void
755 write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
756 {
757     u8 *fdata = vgafont8;
758     u16 addr = (xcurs * bpp) + ycurs * 320;
759     u16 src = car * 8;
760     u8 i;
761     for (i = 0; i < 8; i++) {
762         u8 *dest = (void*)(addr + (i >> 1) * 80);
763         if (i & 1)
764             dest += 0x2000;
765         u8 mask = 0x80;
766         if (bpp == 1) {
767             u8 data = 0;
768             if (attr & 0x80)
769                 data = GET_FARVAR(0xb800, *dest);
770             u8 j;
771             for (j = 0; j < 8; j++) {
772                 if (GET_GLOBAL(fdata[src + i]) & mask) {
773                     if (attr & 0x80)
774                         data ^= (attr & 0x01) << (7 - j);
775                     else
776                         data |= (attr & 0x01) << (7 - j);
777                 }
778                 mask >>= 1;
779             }
780             SET_FARVAR(0xb800, *dest, data);
781         } else {
782             while (mask > 0) {
783                 u8 data = 0;
784                 if (attr & 0x80)
785                     data = GET_FARVAR(0xb800, *dest);
786                 u8 j;
787                 for (j = 0; j < 4; j++) {
788                     if (GET_GLOBAL(fdata[src + i]) & mask) {
789                         if (attr & 0x80)
790                             data ^= (attr & 0x03) << ((3 - j) * 2);
791                         else
792                             data |= (attr & 0x03) << ((3 - j) * 2);
793                     }
794                     mask >>= 1;
795                 }
796                 SET_FARVAR(0xb800, *dest, data);
797                 dest += 1;
798             }
799         }
800     }
801 }
802
803 // -------------------------------------------------------------------
804 static void
805 write_gfx_char_lin(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols)
806 {
807     u8 *fdata = vgafont8;
808     u16 addr = xcurs * 8 + ycurs * nbcols * 64;
809     u16 src = car * 8;
810     u8 i;
811     for (i = 0; i < 8; i++) {
812         u8 *dest = (void*)(addr + i * nbcols * 8);
813         u8 mask = 0x80;
814         u8 j;
815         for (j = 0; j < 8; j++) {
816             u8 data = 0x00;
817             if (GET_GLOBAL(fdata[src + i]) & mask)
818                 data = attr;
819             SET_FARVAR(0xa000, dest[j], data);
820             mask >>= 1;
821         }
822     }
823 }
824
825 // -------------------------------------------------------------------
826 static void
827 biosfn_write_char_attr(u8 car, u8 page, u8 attr, u16 count)
828 {
829     u8 cheight, xcurs, ycurs, mode, line, bpp;
830     u16 nbcols, nbrows;
831     u16 cursor, dummy;
832
833     // Get the mode
834     mode = GET_BDA(video_mode);
835     line = find_vga_entry(mode);
836     if (line == 0xFF)
837         return;
838
839     // Get the cursor pos for the page
840     biosfn_get_cursor_pos(page, &dummy, &cursor);
841     xcurs = cursor & 0x00ff;
842     ycurs = (cursor & 0xff00) >> 8;
843
844     // Get the dimensions
845     nbrows = GET_BDA(video_rows) + 1;
846     nbcols = GET_BDA(video_cols);
847
848     if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
849         // Compute the address
850         void *address = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
851                                 + (xcurs + ycurs * nbcols) * 2);
852
853         dummy = ((u16)attr << 8) + car;
854         memset16_far(GET_GLOBAL(vga_modes[line].sstart), address, dummy
855                      , count * 2);
856     } else {
857         // FIXME gfx mode not complete
858         cheight = GET_GLOBAL(video_param_table[GET_GLOBAL(line_to_vpti[line])].cheight);
859         bpp = GET_GLOBAL(vga_modes[line].pixbits);
860         while ((count-- > 0) && (xcurs < nbcols)) {
861             switch (GET_GLOBAL(vga_modes[line].memmodel)) {
862             case PLANAR4:
863             case PLANAR1:
864                 write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols,
865                                    cheight);
866                 break;
867             case CGA:
868                 write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
869                 break;
870             case LINEAR8:
871                 write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
872                 break;
873             }
874             xcurs++;
875         }
876     }
877 }
878
879 // -------------------------------------------------------------------
880 static void
881 biosfn_write_char_only(u8 car, u8 page, u8 attr, u16 count)
882 {
883     u8 cheight, xcurs, ycurs, mode, line, bpp;
884     u16 nbcols, nbrows;
885     u16 cursor, dummy;
886
887     // Get the mode
888     mode = GET_BDA(video_mode);
889     line = find_vga_entry(mode);
890     if (line == 0xFF)
891         return;
892
893     // Get the cursor pos for the page
894     biosfn_get_cursor_pos(page, &dummy, &cursor);
895     xcurs = cursor & 0x00ff;
896     ycurs = (cursor & 0xff00) >> 8;
897
898     // Get the dimensions
899     nbrows = GET_BDA(video_rows) + 1;
900     nbcols = GET_BDA(video_cols);
901
902     if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
903         // Compute the address
904         u8 *address = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
905                               + (xcurs + ycurs * nbcols) * 2);
906         while (count-- > 0) {
907             SET_FARVAR(GET_GLOBAL(vga_modes[line].sstart), *address, car);
908             address += 2;
909         }
910     } else {
911         // FIXME gfx mode not complete
912         cheight = GET_GLOBAL(video_param_table[GET_GLOBAL(line_to_vpti[line])].cheight);
913         bpp = GET_GLOBAL(vga_modes[line].pixbits);
914         while ((count-- > 0) && (xcurs < nbcols)) {
915             switch (GET_GLOBAL(vga_modes[line].memmodel)) {
916             case PLANAR4:
917             case PLANAR1:
918                 write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols,
919                                    cheight);
920                 break;
921             case CGA:
922                 write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
923                 break;
924             case LINEAR8:
925                 write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
926                 break;
927             }
928             xcurs++;
929         }
930     }
931 }
932
933
934
935 // -------------------------------------------------------------------
936 static void
937 biosfn_set_border_color(struct bregs *regs)
938 {
939     inb(VGAREG_ACTL_RESET);
940     outb(0x00, VGAREG_ACTL_ADDRESS);
941     u8 al = regs->bl & 0x0f;
942     if (al & 0x08)
943         al += 0x08;
944     outb(al, VGAREG_ACTL_WRITE_DATA);
945     u8 bl = regs->bl & 0x10;
946
947     int i;
948     for (i = 1; i < 4; i++) {
949         outb(i, VGAREG_ACTL_ADDRESS);
950
951         al = inb(VGAREG_ACTL_READ_DATA);
952         al &= 0xef;
953         al |= bl;
954         outb(al, VGAREG_ACTL_WRITE_DATA);
955     }
956     outb(0x20, VGAREG_ACTL_ADDRESS);
957 }
958
959 static void
960 biosfn_set_palette(struct bregs *regs)
961 {
962     inb(VGAREG_ACTL_RESET);
963     u8 bl = regs->bl & 0x01;
964     int i;
965     for (i = 1; i < 4; i++) {
966         outb(i, VGAREG_ACTL_ADDRESS);
967
968         u8 al = inb(VGAREG_ACTL_READ_DATA);
969         al &= 0xfe;
970         al |= bl;
971         outb(al, VGAREG_ACTL_WRITE_DATA);
972     }
973     outb(0x20, VGAREG_ACTL_ADDRESS);
974 }
975
976 // -------------------------------------------------------------------
977 static void
978 biosfn_write_pixel(u8 BH, u8 AL, u16 CX, u16 DX)
979 {
980     u8 mask, attr, data;
981
982     // Get the mode
983     u8 mode = GET_BDA(video_mode);
984     u8 line = find_vga_entry(mode);
985     if (line == 0xFF)
986         return;
987     if (GET_GLOBAL(vga_modes[line].class) == TEXT)
988         return;
989
990     u8 *addr;
991     switch (GET_GLOBAL(vga_modes[line].memmodel)) {
992     case PLANAR4:
993     case PLANAR1:
994         addr = (void*)(CX / 8 + DX * GET_BDA(video_cols));
995         mask = 0x80 >> (CX & 0x07);
996         outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
997         outw(0x0205, VGAREG_GRDC_ADDRESS);
998         data = GET_FARVAR(0xa000, *addr);
999         if (AL & 0x80)
1000             outw(0x1803, VGAREG_GRDC_ADDRESS);
1001         SET_FARVAR(0xa000, *addr, AL);
1002         outw(0xff08, VGAREG_GRDC_ADDRESS);
1003         outw(0x0005, VGAREG_GRDC_ADDRESS);
1004         outw(0x0003, VGAREG_GRDC_ADDRESS);
1005         break;
1006     case CGA:
1007         if (GET_GLOBAL(vga_modes[line].pixbits) == 2)
1008             addr = (void*)((CX >> 2) + (DX >> 1) * 80);
1009         else
1010             addr = (void*)((CX >> 3) + (DX >> 1) * 80);
1011         if (DX & 1)
1012             addr += 0x2000;
1013         data = GET_FARVAR(0xb800, *addr);
1014         if (GET_GLOBAL(vga_modes[line].pixbits) == 2) {
1015             attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
1016             mask = 0x03 << ((3 - (CX & 0x03)) * 2);
1017         } else {
1018             attr = (AL & 0x01) << (7 - (CX & 0x07));
1019             mask = 0x01 << (7 - (CX & 0x07));
1020         }
1021         if (AL & 0x80) {
1022             data ^= attr;
1023         } else {
1024             data &= ~mask;
1025             data |= attr;
1026         }
1027         SET_FARVAR(0xb800, *addr, data);
1028         break;
1029     case LINEAR8:
1030         addr = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
1031         SET_FARVAR(0xa000, *addr, AL);
1032         break;
1033     }
1034 }
1035
1036 // -------------------------------------------------------------------
1037 static void
1038 biosfn_read_pixel(u8 BH, u16 CX, u16 DX, u16 *AX)
1039 {
1040     u8 mode, line, mask, attr, data, i;
1041
1042     // Get the mode
1043     mode = GET_BDA(video_mode);
1044     line = find_vga_entry(mode);
1045     if (line == 0xFF)
1046         return;
1047     if (GET_GLOBAL(vga_modes[line].class) == TEXT)
1048         return;
1049
1050     u8 *addr;
1051     switch (GET_GLOBAL(vga_modes[line].memmodel)) {
1052     case PLANAR4:
1053     case PLANAR1:
1054         addr = (void*)(CX / 8 + DX * GET_BDA(video_cols));
1055         mask = 0x80 >> (CX & 0x07);
1056         attr = 0x00;
1057         for (i = 0; i < 4; i++) {
1058             outw((i << 8) | 0x04, VGAREG_GRDC_ADDRESS);
1059             data = GET_FARVAR(0xa000, *addr) & mask;
1060             if (data > 0)
1061                 attr |= (0x01 << i);
1062         }
1063         break;
1064     case CGA:
1065         addr = (void*)((CX >> 2) + (DX >> 1) * 80);
1066         if (DX & 1)
1067             addr += 0x2000;
1068         data = GET_FARVAR(0xb800, *addr);
1069         if (GET_GLOBAL(vga_modes[line].pixbits) == 2)
1070             attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
1071         else
1072             attr = (data >> (7 - (CX & 0x07))) & 0x01;
1073         break;
1074     case LINEAR8:
1075         addr = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
1076         attr = GET_FARVAR(0xa000, *addr);
1077         break;
1078     }
1079     *AX = (*AX & 0xff00) | attr;
1080 }
1081
1082 // -------------------------------------------------------------------
1083 static void
1084 biosfn_write_teletype(u8 car, u8 page, u8 attr, u8 flag)
1085 {                               // flag = WITH_ATTR / NO_ATTR
1086     u8 cheight, xcurs, ycurs, mode, line, bpp;
1087     u16 nbcols, nbrows;
1088     u16 cursor, dummy;
1089
1090     // special case if page is 0xff, use current page
1091     if (page == 0xff)
1092         page = GET_BDA(video_page);
1093
1094     // Get the mode
1095     mode = GET_BDA(video_mode);
1096     line = find_vga_entry(mode);
1097     if (line == 0xFF)
1098         return;
1099
1100     // Get the cursor pos for the page
1101     biosfn_get_cursor_pos(page, &dummy, &cursor);
1102     xcurs = cursor & 0x00ff;
1103     ycurs = (cursor & 0xff00) >> 8;
1104
1105     // Get the dimensions
1106     nbrows = GET_BDA(video_rows) + 1;
1107     nbcols = GET_BDA(video_cols);
1108
1109     switch (car) {
1110     case 7:
1111         //FIXME should beep
1112         break;
1113
1114     case 8:
1115         if (xcurs > 0)
1116             xcurs--;
1117         break;
1118
1119     case '\r':
1120         xcurs = 0;
1121         break;
1122
1123     case '\n':
1124         ycurs++;
1125         break;
1126
1127     case '\t':
1128         do {
1129             biosfn_write_teletype(' ', page, attr, flag);
1130             biosfn_get_cursor_pos(page, &dummy, &cursor);
1131             xcurs = cursor & 0x00ff;
1132             ycurs = (cursor & 0xff00) >> 8;
1133         } while (xcurs % 8 == 0);
1134         break;
1135
1136     default:
1137
1138         if (GET_GLOBAL(vga_modes[line].class) == TEXT) {
1139             // Compute the address
1140             u8 *address = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
1141                                   + (xcurs + ycurs * nbcols) * 2);
1142             // Write the char
1143             SET_FARVAR(GET_GLOBAL(vga_modes[line].sstart), address[0], car);
1144             if (flag == WITH_ATTR)
1145                 SET_FARVAR(GET_GLOBAL(vga_modes[line].sstart), address[1], attr);
1146         } else {
1147             // FIXME gfx mode not complete
1148             cheight = GET_GLOBAL(video_param_table[GET_GLOBAL(line_to_vpti[line])].cheight);
1149             bpp = GET_GLOBAL(vga_modes[line].pixbits);
1150             switch (GET_GLOBAL(vga_modes[line].memmodel)) {
1151             case PLANAR4:
1152             case PLANAR1:
1153                 write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols,
1154                                    cheight);
1155                 break;
1156             case CGA:
1157                 write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
1158                 break;
1159             case LINEAR8:
1160                 write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
1161                 break;
1162             }
1163         }
1164         xcurs++;
1165     }
1166
1167     // Do we need to wrap ?
1168     if (xcurs == nbcols) {
1169         xcurs = 0;
1170         ycurs++;
1171     }
1172     // Do we need to scroll ?
1173     if (ycurs == nbrows) {
1174         if (GET_GLOBAL(vga_modes[line].class) == TEXT)
1175             biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, page,
1176                           SCROLL_UP);
1177         else
1178             biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, page,
1179                           SCROLL_UP);
1180         ycurs -= 1;
1181     }
1182     // Set the cursor for the page
1183     cursor = ycurs;
1184     cursor <<= 8;
1185     cursor += xcurs;
1186     biosfn_set_cursor_pos(page, cursor);
1187 }
1188
1189 // -------------------------------------------------------------------
1190 static void
1191 biosfn_get_video_mode(struct bregs *regs)
1192 {
1193     regs->bh = GET_BDA(video_page);
1194     regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
1195     regs->ah = GET_BDA(video_cols);
1196 }
1197
1198 // -------------------------------------------------------------------
1199 static void
1200 biosfn_set_overscan_border_color(struct bregs *regs)
1201 {
1202     inb(VGAREG_ACTL_RESET);
1203     outb(0x11, VGAREG_ACTL_ADDRESS);
1204     outb(regs->bh, VGAREG_ACTL_WRITE_DATA);
1205     outb(0x20, VGAREG_ACTL_ADDRESS);
1206 }
1207
1208 // -------------------------------------------------------------------
1209 static void
1210 biosfn_set_all_palette_reg(struct bregs *regs)
1211 {
1212     inb(VGAREG_ACTL_RESET);
1213
1214     u8 *data = (u8*)(regs->dx + 0);
1215     int i;
1216     for (i = 0; i < 0x10; i++) {
1217         outb(i, VGAREG_ACTL_ADDRESS);
1218         u8 val = GET_FARVAR(regs->es, *data);
1219         outb(val, VGAREG_ACTL_WRITE_DATA);
1220         data++;
1221     }
1222     outb(0x11, VGAREG_ACTL_ADDRESS);
1223     outb(GET_FARVAR(regs->es, *data), VGAREG_ACTL_WRITE_DATA);
1224     outb(0x20, VGAREG_ACTL_ADDRESS);
1225 }
1226
1227 // -------------------------------------------------------------------
1228 static void
1229 biosfn_toggle_intensity(struct bregs *regs)
1230 {
1231     inb(VGAREG_ACTL_RESET);
1232     outb(0x10, VGAREG_ACTL_ADDRESS);
1233     u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0x7f) | ((regs->bl & 0x01) << 3);
1234     outb(val, VGAREG_ACTL_WRITE_DATA);
1235     outb(0x20, VGAREG_ACTL_ADDRESS);
1236 }
1237
1238 // -------------------------------------------------------------------
1239 void
1240 biosfn_set_single_palette_reg(u8 reg, u8 val)
1241 {
1242     inb(VGAREG_ACTL_RESET);
1243     outb(reg, VGAREG_ACTL_ADDRESS);
1244     outb(val, VGAREG_ACTL_WRITE_DATA);
1245     outb(0x20, VGAREG_ACTL_ADDRESS);
1246 }
1247
1248 // -------------------------------------------------------------------
1249 u8
1250 biosfn_get_single_palette_reg(u8 reg)
1251 {
1252     inb(VGAREG_ACTL_RESET);
1253     outb(reg, VGAREG_ACTL_ADDRESS);
1254     u8 v = inb(VGAREG_ACTL_READ_DATA);
1255     inb(VGAREG_ACTL_RESET);
1256     outb(0x20, VGAREG_ACTL_ADDRESS);
1257     return v;
1258 }
1259
1260 // -------------------------------------------------------------------
1261 static void
1262 biosfn_read_overscan_border_color(struct bregs *regs)
1263 {
1264     inb(VGAREG_ACTL_RESET);
1265     outb(0x11, VGAREG_ACTL_ADDRESS);
1266     regs->bh = inb(VGAREG_ACTL_READ_DATA);
1267     inb(VGAREG_ACTL_RESET);
1268     outb(0x20, VGAREG_ACTL_ADDRESS);
1269 }
1270
1271 // -------------------------------------------------------------------
1272 static void
1273 biosfn_get_all_palette_reg(struct bregs *regs)
1274 {
1275     u8 *data = (u8*)(regs->dx + 0);
1276     int i;
1277     for (i = 0; i < 0x10; i++) {
1278         inb(VGAREG_ACTL_RESET);
1279         outb(i, VGAREG_ACTL_ADDRESS);
1280         SET_FARVAR(regs->es, *data, inb(VGAREG_ACTL_READ_DATA));
1281         data++;
1282     }
1283     inb(VGAREG_ACTL_RESET);
1284     outb(0x11, VGAREG_ACTL_ADDRESS);
1285     SET_FARVAR(regs->es, *data, inb(VGAREG_ACTL_READ_DATA));
1286     inb(VGAREG_ACTL_RESET);
1287     outb(0x20, VGAREG_ACTL_ADDRESS);
1288 }
1289
1290 // -------------------------------------------------------------------
1291 static void
1292 biosfn_set_single_dac_reg(struct bregs *regs)
1293 {
1294     outb(regs->bl, VGAREG_DAC_WRITE_ADDRESS);
1295     outb(regs->dh, VGAREG_DAC_DATA);
1296     outb(regs->ch, VGAREG_DAC_DATA);
1297     outb(regs->cl, VGAREG_DAC_DATA);
1298 }
1299
1300 // -------------------------------------------------------------------
1301 static void
1302 biosfn_set_all_dac_reg(struct bregs *regs)
1303 {
1304     outb(regs->bl, VGAREG_DAC_WRITE_ADDRESS);
1305     u8 *data = (u8*)(regs->dx + 0);
1306     int count = regs->cx;
1307     while (count) {
1308         outb(GET_FARVAR(regs->es, *data), VGAREG_DAC_DATA);
1309         data++;
1310         outb(GET_FARVAR(regs->es, *data), VGAREG_DAC_DATA);
1311         data++;
1312         outb(GET_FARVAR(regs->es, *data), VGAREG_DAC_DATA);
1313         data++;
1314         count--;
1315     }
1316 }
1317
1318 // -------------------------------------------------------------------
1319 static void
1320 biosfn_select_video_dac_color_page(struct bregs *regs)
1321 {
1322     inb(VGAREG_ACTL_RESET);
1323     outb(0x10, VGAREG_ACTL_ADDRESS);
1324     u8 val = inb(VGAREG_ACTL_READ_DATA);
1325     if (!(regs->bl & 0x01)) {
1326         val = (val & 0x7f) | (regs->bh << 7);
1327         outb(val, VGAREG_ACTL_WRITE_DATA);
1328         outb(0x20, VGAREG_ACTL_ADDRESS);
1329         return;
1330     }
1331     inb(VGAREG_ACTL_RESET);
1332     outb(0x14, VGAREG_ACTL_ADDRESS);
1333     u8 bh = regs->bh;
1334     if (!(val & 0x80))
1335         bh <<= 2;
1336     bh &= 0x0f;
1337     outb(bh, VGAREG_ACTL_WRITE_DATA);
1338     outb(0x20, VGAREG_ACTL_ADDRESS);
1339 }
1340
1341 // -------------------------------------------------------------------
1342 static void
1343 biosfn_read_single_dac_reg(struct bregs *regs)
1344 {
1345     outb(regs->bl, VGAREG_DAC_READ_ADDRESS);
1346     regs->dh = inb(VGAREG_DAC_DATA);
1347     regs->ch = inb(VGAREG_DAC_DATA);
1348     regs->cl = inb(VGAREG_DAC_DATA);
1349 }
1350
1351 // -------------------------------------------------------------------
1352 static void
1353 biosfn_read_all_dac_reg(struct bregs *regs)
1354 {
1355     outb(regs->bl, VGAREG_DAC_READ_ADDRESS);
1356     u8 *data = (u8*)(regs->dx + 0);
1357     int count = regs->cx;
1358     while (count) {
1359         SET_FARVAR(regs->es, *data, inb(VGAREG_DAC_DATA));
1360         data++;
1361         SET_FARVAR(regs->es, *data, inb(VGAREG_DAC_DATA));
1362         data++;
1363         SET_FARVAR(regs->es, *data, inb(VGAREG_DAC_DATA));
1364         data++;
1365         count--;
1366     }
1367 }
1368
1369 // -------------------------------------------------------------------
1370 static void
1371 biosfn_set_pel_mask(struct bregs *regs)
1372 {
1373     outb(regs->bl, VGAREG_PEL_MASK);
1374 }
1375
1376 // -------------------------------------------------------------------
1377 static void
1378 biosfn_read_pel_mask(struct bregs *regs)
1379 {
1380     regs->bl = inb(VGAREG_PEL_MASK);
1381 }
1382
1383 // -------------------------------------------------------------------
1384 static void
1385 biosfn_read_video_dac_state(struct bregs *regs)
1386 {
1387     inb(VGAREG_ACTL_RESET);
1388     outb(0x10, VGAREG_ACTL_ADDRESS);
1389     u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
1390
1391     inb(VGAREG_ACTL_RESET);
1392     outb(0x14, VGAREG_ACTL_ADDRESS);
1393     u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
1394     if (!(val1 & 0x01))
1395         val2 >>= 2;
1396
1397     inb(VGAREG_ACTL_RESET);
1398     outb(0x20, VGAREG_ACTL_ADDRESS);
1399
1400     regs->bl = val1;
1401     regs->bh = val2;
1402 }
1403
1404 // -------------------------------------------------------------------
1405 static void
1406 get_font_access()
1407 {
1408     outw(0x0100, VGAREG_SEQU_ADDRESS);
1409     outw(0x0402, VGAREG_SEQU_ADDRESS);
1410     outw(0x0704, VGAREG_SEQU_ADDRESS);
1411     outw(0x0300, VGAREG_SEQU_ADDRESS);
1412     outw(0x0204, VGAREG_GRDC_ADDRESS);
1413     outw(0x0005, VGAREG_GRDC_ADDRESS);
1414     outw(0x0406, VGAREG_GRDC_ADDRESS);
1415 }
1416
1417 static void
1418 release_font_access()
1419 {
1420     outw(0x0100, VGAREG_SEQU_ADDRESS);
1421     outw(0x0302, VGAREG_SEQU_ADDRESS);
1422     outw(0x0304, VGAREG_SEQU_ADDRESS);
1423     outw(0x0300, VGAREG_SEQU_ADDRESS);
1424     u16 v = inw(VGAREG_READ_MISC_OUTPUT);
1425     v = ((v & 0x01) << 10) | 0x0a06;
1426     outw(v, VGAREG_GRDC_ADDRESS);
1427     outw(0x0004, VGAREG_GRDC_ADDRESS);
1428     outw(0x1005, VGAREG_GRDC_ADDRESS);
1429 }
1430
1431 static void
1432 set_scan_lines(u8 lines)
1433 {
1434     u16 crtc_addr, cols, vde;
1435     u8 crtc_r9, ovl, rows;
1436
1437     crtc_addr = GET_BDA(crtc_address);
1438     outb(0x09, crtc_addr);
1439     crtc_r9 = inb(crtc_addr + 1);
1440     crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
1441     outb(crtc_r9, crtc_addr + 1);
1442     if (lines == 8)
1443         biosfn_set_cursor_shape(0x06, 0x07);
1444     else
1445         biosfn_set_cursor_shape(lines - 4, lines - 3);
1446     SET_BDA(char_height, lines);
1447     outb(0x12, crtc_addr);
1448     vde = inb(crtc_addr + 1);
1449     outb(0x07, crtc_addr);
1450     ovl = inb(crtc_addr + 1);
1451     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
1452     rows = vde / lines;
1453     SET_BDA(video_rows, rows - 1);
1454     cols = GET_BDA(video_cols);
1455     SET_BDA(video_pagesize, rows * cols * 2);
1456 }
1457
1458 static void
1459 biosfn_load_text_user_pat(u8 AL, u16 ES, u16 BP, u16 CX, u16 DX, u8 BL,
1460                           u8 BH)
1461 {
1462     get_font_access();
1463     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1464     u16 i;
1465     for (i = 0; i < CX; i++) {
1466         void *src = (void*)(BP + i * BH);
1467         void *dest = (void*)(blockaddr + (DX + i) * 32);
1468         memcpy_far(0xA000, dest, ES, src, BH);
1469     }
1470     release_font_access();
1471     if (AL >= 0x10)
1472         set_scan_lines(BH);
1473 }
1474
1475 static void
1476 biosfn_load_text_8_14_pat(u8 AL, u8 BL)
1477 {
1478     get_font_access();
1479     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1480     u16 i;
1481     for (i = 0; i < 0x100; i++) {
1482         u16 src = i * 14;
1483         void *dest = (void*)(blockaddr + i * 32);
1484         memcpy_far(0xA000, dest, 0xC000, &vgafont14[src], 14);
1485     }
1486     release_font_access();
1487     if (AL >= 0x10)
1488         set_scan_lines(14);
1489 }
1490
1491 static void
1492 biosfn_load_text_8_8_pat(u8 AL, u8 BL)
1493 {
1494     get_font_access();
1495     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1496     u16 i;
1497     for (i = 0; i < 0x100; i++) {
1498         u16 src = i * 8;
1499         void *dest = (void*)(blockaddr + i * 32);
1500         memcpy_far(0xA000, dest, 0xC000, &vgafont8[src], 8);
1501     }
1502     release_font_access();
1503     if (AL >= 0x10)
1504         set_scan_lines(8);
1505 }
1506
1507 // -------------------------------------------------------------------
1508 static void
1509 biosfn_set_text_block_specifier(struct bregs *regs)
1510 {
1511     outw((regs->bl << 8) | 0x03, VGAREG_SEQU_ADDRESS);
1512 }
1513
1514 // -------------------------------------------------------------------
1515 static void
1516 biosfn_load_text_8_16_pat(u8 AL, u8 BL)
1517 {
1518     get_font_access();
1519     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1520     u16 i;
1521     for (i = 0; i < 0x100; i++) {
1522         u16 src = i * 16;
1523         void *dest = (void*)(blockaddr + i * 32);
1524         memcpy_far(0xA000, dest, 0xC000, &vgafont16[src], 16);
1525     }
1526     release_font_access();
1527     if (AL >= 0x10)
1528         set_scan_lines(16);
1529 }
1530
1531 // -------------------------------------------------------------------
1532 static void
1533 biosfn_get_font_info(u8 BH, u16 *ES, u16 *BP, u16 *CX, u16 *DX)
1534 {
1535     switch (BH) {
1536     case 0x00: {
1537         u32 segoff = GET_IVT(0x1f).segoff;
1538         *ES = segoff >> 16;
1539         *BP = segoff;
1540         break;
1541     }
1542     case 0x01: {
1543         u32 segoff = GET_IVT(0x43).segoff;
1544         *ES = segoff >> 16;
1545         *BP = segoff;
1546         break;
1547     }
1548     case 0x02:
1549         *ES = 0xC000;
1550         *BP = (u32)vgafont14;
1551         break;
1552     case 0x03:
1553         *ES = 0xC000;
1554         *BP = (u32)vgafont8;
1555         break;
1556     case 0x04:
1557         *ES = 0xC000;
1558         *BP = (u32)vgafont8 + 128 * 8;
1559         break;
1560     case 0x05:
1561         *ES = 0xC000;
1562         *BP = (u32)vgafont14alt;
1563         break;
1564     case 0x06:
1565         *ES = 0xC000;
1566         *BP = (u32)vgafont16;
1567         break;
1568     case 0x07:
1569         *ES = 0xC000;
1570         *BP = (u32)vgafont16alt;
1571         break;
1572     default:
1573         dprintf(1, "Get font info BH(%02x) was discarded\n", BH);
1574         return;
1575     }
1576     // Set byte/char of on screen font
1577     *CX = GET_BDA(char_height) & 0xff;
1578
1579     // Set Highest char row
1580     *DX = GET_BDA(video_rows);
1581 }
1582
1583 // -------------------------------------------------------------------
1584 static void
1585 biosfn_get_ega_info(struct bregs *regs)
1586 {
1587     regs->cx = GET_BDA(video_switches) & 0x0f;
1588     regs->ax = GET_BDA(crtc_address);
1589     if (regs->ax == VGAREG_MDA_CRTC_ADDRESS)
1590         regs->bx = 0x0103;
1591     else
1592         regs->bx = 0x0003;
1593 }
1594
1595 // -------------------------------------------------------------------
1596 static void
1597 biosfn_select_vert_res(struct bregs *regs)
1598 {
1599     u8 mctl = GET_BDA(modeset_ctl);
1600     u8 vswt = GET_BDA(video_switches);
1601
1602     switch (regs->al) {
1603     case 0x00:
1604         // 200 lines
1605         mctl = (mctl & ~0x10) | 0x80;
1606         vswt = (vswt & ~0x0f) | 0x08;
1607         break;
1608     case 0x01:
1609         // 350 lines
1610         mctl &= ~0x90;
1611         vswt = (vswt & ~0x0f) | 0x09;
1612         break;
1613     case 0x02:
1614         // 400 lines
1615         mctl = (mctl & ~0x80) | 0x10;
1616         vswt = (vswt & ~0x0f) | 0x09;
1617         break;
1618     default:
1619         dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
1620         break;
1621     }
1622     SET_BDA(modeset_ctl, mctl);
1623     SET_BDA(video_switches, vswt);
1624     regs->ax = 0x1212;
1625 }
1626
1627 static void
1628 biosfn_enable_default_palette_loading(struct bregs *regs)
1629 {
1630     u8 v = (regs->al & 0x01) << 3;
1631     u8 mctl = GET_BDA(video_ctl) & ~0x08;
1632     SET_BDA(video_ctl, mctl | v);
1633     regs->ax = 0x1212;
1634 }
1635
1636 static void
1637 biosfn_enable_video_addressing(struct bregs *regs)
1638 {
1639     u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
1640     u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
1641     outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
1642     regs->ax = 0x1212;
1643 }
1644
1645
1646 static void
1647 biosfn_enable_grayscale_summing(struct bregs *regs)
1648 {
1649     u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
1650     u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
1651     SET_BDA(modeset_ctl, v | v2);
1652     regs->ax = 0x1212;
1653 }
1654
1655 static void
1656 biosfn_enable_cursor_emulation(struct bregs *regs)
1657 {
1658     u8 v = (regs->al & 0x01) ^ 0x01;
1659     u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
1660     SET_BDA(modeset_ctl, v | v2);
1661     regs->ax = 0x1212;
1662 }
1663
1664 // -------------------------------------------------------------------
1665 static void
1666 biosfn_write_string(u8 flag, u8 page, u8 attr, u16 count, u8 row, u8 col,
1667                     u16 seg, u8 *offset)
1668 {
1669     u16 newcurs, oldcurs, dummy;
1670     u8 car;
1671
1672     // Read curs info for the page
1673     biosfn_get_cursor_pos(page, &dummy, &oldcurs);
1674
1675     // if row=0xff special case : use current cursor position
1676     if (row == 0xff) {
1677         col = oldcurs & 0x00ff;
1678         row = (oldcurs & 0xff00) >> 8;
1679     }
1680
1681     newcurs = row;
1682     newcurs <<= 8;
1683     newcurs += col;
1684     biosfn_set_cursor_pos(page, newcurs);
1685
1686     while (count-- != 0) {
1687         car = GET_FARVAR(seg, *offset);
1688         offset++;
1689         if ((flag & 0x02) != 0) {
1690             attr = GET_FARVAR(seg, *offset);
1691             offset++;
1692         }
1693
1694         biosfn_write_teletype(car, page, attr, WITH_ATTR);
1695     }
1696
1697     // Set back curs pos
1698     if ((flag & 0x01) == 0)
1699         biosfn_set_cursor_pos(page, oldcurs);
1700 }
1701
1702 // -------------------------------------------------------------------
1703 static void
1704 biosfn_read_display_code(struct bregs *regs)
1705 {
1706     regs->bx = GET_BDA(dcc_index);
1707     regs->al = 0x1a;
1708 }
1709
1710 static void
1711 biosfn_set_display_code(struct bregs *regs)
1712 {
1713     SET_BDA(dcc_index, regs->bl);
1714     dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
1715     regs->al = 0x1a;
1716 }
1717
1718 // -------------------------------------------------------------------
1719 static void
1720 biosfn_read_state_info(u16 BX, u16 ES, u16 DI)
1721 {
1722     // Address of static functionality table
1723     SET_FARVAR(ES, *(u16*)(DI + 0x00), (u32)static_functionality);
1724     SET_FARVAR(ES, *(u16*)(DI + 0x02), 0xC000);
1725
1726     // Hard coded copy from BIOS area. Should it be cleaner ?
1727     memcpy_far(ES, (void*)(DI + 0x04), SEG_BDA, (void*)0x49, 30);
1728     memcpy_far(ES, (void*)(DI + 0x22), SEG_BDA, (void*)0x84, 3);
1729
1730     SET_FARVAR(ES, *(u8*)(DI + 0x25), GET_BDA(dcc_index));
1731     SET_FARVAR(ES, *(u8*)(DI + 0x26), 0);
1732     SET_FARVAR(ES, *(u8*)(DI + 0x27), 16);
1733     SET_FARVAR(ES, *(u8*)(DI + 0x28), 0);
1734     SET_FARVAR(ES, *(u8*)(DI + 0x29), 8);
1735     SET_FARVAR(ES, *(u8*)(DI + 0x2a), 2);
1736     SET_FARVAR(ES, *(u8*)(DI + 0x2b), 0);
1737     SET_FARVAR(ES, *(u8*)(DI + 0x2c), 0);
1738     SET_FARVAR(ES, *(u8*)(DI + 0x31), 3);
1739     SET_FARVAR(ES, *(u8*)(DI + 0x32), 0);
1740
1741     memset_far(ES, (void*)(DI + 0x33), 0, 13);
1742 }
1743
1744 // -------------------------------------------------------------------
1745 // -------------------------------------------------------------------
1746 static u16
1747 biosfn_read_video_state_size(u16 CX)
1748 {
1749     u16 size = 0;
1750     if (CX & 1)
1751         size += 0x46;
1752     if (CX & 2)
1753         size += (5 + 8 + 5) * 2 + 6;
1754     if (CX & 4)
1755         size += 3 + 256 * 3 + 1;
1756     return size;
1757 }
1758
1759 static u16
1760 biosfn_save_video_state(u16 CX, u16 ES, u16 BX)
1761 {
1762     u16 i, crtc_addr, ar_index;
1763
1764     crtc_addr = GET_BDA(crtc_address);
1765     if (CX & 1) {
1766         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_ADDRESS));
1767         BX++;
1768         SET_FARVAR(ES, *(u8*)(BX+0), inb(crtc_addr));
1769         BX++;
1770         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_GRDC_ADDRESS));
1771         BX++;
1772         inb(VGAREG_ACTL_RESET);
1773         ar_index = inb(VGAREG_ACTL_ADDRESS);
1774         SET_FARVAR(ES, *(u8*)(BX+0), ar_index);
1775         BX++;
1776         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_READ_FEATURE_CTL));
1777         BX++;
1778
1779         for (i = 1; i <= 4; i++) {
1780             outb(i, VGAREG_SEQU_ADDRESS);
1781             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_DATA));
1782             BX++;
1783         }
1784         outb(0, VGAREG_SEQU_ADDRESS);
1785         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_DATA));
1786         BX++;
1787
1788         for (i = 0; i <= 0x18; i++) {
1789             outb(i, crtc_addr);
1790             SET_FARVAR(ES, *(u8*)(BX+0), inb(crtc_addr + 1));
1791             BX++;
1792         }
1793
1794         for (i = 0; i <= 0x13; i++) {
1795             inb(VGAREG_ACTL_RESET);
1796             outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
1797             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_ACTL_READ_DATA));
1798             BX++;
1799         }
1800         inb(VGAREG_ACTL_RESET);
1801
1802         for (i = 0; i <= 8; i++) {
1803             outb(i, VGAREG_GRDC_ADDRESS);
1804             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_GRDC_DATA));
1805             BX++;
1806         }
1807
1808         SET_FARVAR(ES, *(u16*)(BX+0), crtc_addr);
1809         BX += 2;
1810
1811         /* XXX: read plane latches */
1812         SET_FARVAR(ES, *(u8*)(BX+0), 0);
1813         BX++;
1814         SET_FARVAR(ES, *(u8*)(BX+0), 0);
1815         BX++;
1816         SET_FARVAR(ES, *(u8*)(BX+0), 0);
1817         BX++;
1818         SET_FARVAR(ES, *(u8*)(BX+0), 0);
1819         BX++;
1820     }
1821     if (CX & 2) {
1822         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_mode));
1823         BX++;
1824         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_cols));
1825         BX += 2;
1826         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_pagesize));
1827         BX += 2;
1828         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(crtc_address));
1829         BX += 2;
1830         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_rows));
1831         BX++;
1832         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(char_height));
1833         BX += 2;
1834         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_ctl));
1835         BX++;
1836         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_switches));
1837         BX++;
1838         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(modeset_ctl));
1839         BX++;
1840         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(cursor_type));
1841         BX += 2;
1842         for (i = 0; i < 8; i++) {
1843             SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(cursor_pos[i]));
1844             BX += 2;
1845         }
1846         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_pagestart));
1847         BX += 2;
1848         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_page));
1849         BX++;
1850         /* current font */
1851         SET_FARVAR(ES, *(u16*)(BX+0), GET_FARVAR(0, *(u16*)(0x1f * 4)));
1852         BX += 2;
1853         SET_FARVAR(ES, *(u16*)(BX+0), GET_FARVAR(0, *(u16*)(0x1f * 4 + 2)));
1854         BX += 2;
1855         SET_FARVAR(ES, *(u16*)(BX+0), GET_FARVAR(0, *(u16*)(0x43 * 4)));
1856         BX += 2;
1857         SET_FARVAR(ES, *(u16*)(BX+0), GET_FARVAR(0, *(u16*)(0x43 * 4 + 2)));
1858         BX += 2;
1859     }
1860     if (CX & 4) {
1861         /* XXX: check this */
1862         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_STATE));
1863         BX++;                   /* read/write mode dac */
1864         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_WRITE_ADDRESS));
1865         BX++;                   /* pix address */
1866         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_PEL_MASK));
1867         BX++;
1868         // Set the whole dac always, from 0
1869         outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
1870         for (i = 0; i < 256 * 3; i++) {
1871             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_DATA));
1872             BX++;
1873         }
1874         SET_FARVAR(ES, *(u8*)(BX+0), 0);
1875         BX++;                   /* color select register */
1876     }
1877     return BX;
1878 }
1879
1880 static u16
1881 biosfn_restore_video_state(u16 CX, u16 ES, u16 BX)
1882 {
1883     u16 i, crtc_addr, v, addr1, ar_index;
1884
1885     if (CX & 1) {
1886         // Reset Attribute Ctl flip-flop
1887         inb(VGAREG_ACTL_RESET);
1888
1889         crtc_addr = GET_FARVAR(ES, *(u16*)(BX + 0x40));
1890         addr1 = BX;
1891         BX += 5;
1892
1893         for (i = 1; i <= 4; i++) {
1894             outb(i, VGAREG_SEQU_ADDRESS);
1895             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_SEQU_DATA);
1896             BX++;
1897         }
1898         outb(0, VGAREG_SEQU_ADDRESS);
1899         outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_SEQU_DATA);
1900         BX++;
1901
1902         // Disable CRTC write protection
1903         outw(0x0011, crtc_addr);
1904         // Set CRTC regs
1905         for (i = 0; i <= 0x18; i++) {
1906             if (i != 0x11) {
1907                 outb(i, crtc_addr);
1908                 outb(GET_FARVAR(ES, *(u8*)(BX+0)), crtc_addr + 1);
1909             }
1910             BX++;
1911         }
1912         // select crtc base address
1913         v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
1914         if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
1915             v |= 0x01;
1916         outb(v, VGAREG_WRITE_MISC_OUTPUT);
1917
1918         // enable write protection if needed
1919         outb(0x11, crtc_addr);
1920         outb(GET_FARVAR(ES, *(u8*)(BX - 0x18 + 0x11)), crtc_addr + 1);
1921
1922         // Set Attribute Ctl
1923         ar_index = GET_FARVAR(ES, *(u8*)(addr1 + 0x03));
1924         inb(VGAREG_ACTL_RESET);
1925         for (i = 0; i <= 0x13; i++) {
1926             outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
1927             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_ACTL_WRITE_DATA);
1928             BX++;
1929         }
1930         outb(ar_index, VGAREG_ACTL_ADDRESS);
1931         inb(VGAREG_ACTL_RESET);
1932
1933         for (i = 0; i <= 8; i++) {
1934             outb(i, VGAREG_GRDC_ADDRESS);
1935             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_GRDC_DATA);
1936             BX++;
1937         }
1938         BX += 2;                /* crtc_addr */
1939         BX += 4;                /* plane latches */
1940
1941         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), VGAREG_SEQU_ADDRESS);
1942         addr1++;
1943         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), crtc_addr);
1944         addr1++;
1945         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), VGAREG_GRDC_ADDRESS);
1946         addr1++;
1947         addr1++;
1948         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), crtc_addr - 0x4 + 0xa);
1949         addr1++;
1950     }
1951     if (CX & 2) {
1952         SET_BDA(video_mode, GET_FARVAR(ES, *(u8*)(BX+0)));
1953         BX++;
1954         SET_BDA(video_cols, GET_FARVAR(ES, *(u16*)(BX+0)));
1955         BX += 2;
1956         SET_BDA(video_pagesize, GET_FARVAR(ES, *(u16*)(BX+0)));
1957         BX += 2;
1958         SET_BDA(crtc_address, GET_FARVAR(ES, *(u16*)(BX+0)));
1959         BX += 2;
1960         SET_BDA(video_rows, GET_FARVAR(ES, *(u8*)(BX+0)));
1961         BX++;
1962         SET_BDA(char_height, GET_FARVAR(ES, *(u16*)(BX+0)));
1963         BX += 2;
1964         SET_BDA(video_ctl, GET_FARVAR(ES, *(u8*)(BX+0)));
1965         BX++;
1966         SET_BDA(video_switches, GET_FARVAR(ES, *(u8*)(BX+0)));
1967         BX++;
1968         SET_BDA(modeset_ctl, GET_FARVAR(ES, *(u8*)(BX+0)));
1969         BX++;
1970         SET_BDA(cursor_type, GET_FARVAR(ES, *(u16*)(BX+0)));
1971         BX += 2;
1972         for (i = 0; i < 8; i++) {
1973             SET_BDA(cursor_pos[i], GET_FARVAR(ES, *(u16*)(BX+0)));
1974             BX += 2;
1975         }
1976         SET_BDA(video_pagestart, GET_FARVAR(ES, *(u16*)(BX+0)));
1977         BX += 2;
1978         SET_BDA(video_page, GET_FARVAR(ES, *(u8*)(BX+0)));
1979         BX++;
1980         /* current font */
1981         SET_IVT(0x1f, GET_FARVAR(ES, *(u16*)(BX+2)), GET_FARVAR(ES, *(u16*)(BX+0)));
1982         BX += 4;
1983         SET_IVT(0x43, GET_FARVAR(ES, *(u16*)(BX+2)), GET_FARVAR(ES, *(u16*)(BX+0)));
1984         BX += 4;
1985     }
1986     if (CX & 4) {
1987         BX++;
1988         v = GET_FARVAR(ES, *(u8*)(BX+0));
1989         BX++;
1990         outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_PEL_MASK);
1991         BX++;
1992         // Set the whole dac always, from 0
1993         outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
1994         for (i = 0; i < 256 * 3; i++) {
1995             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_DAC_DATA);
1996             BX++;
1997         }
1998         BX++;
1999         outb(v, VGAREG_DAC_WRITE_ADDRESS);
2000     }
2001     return BX;
2002 }
2003
2004
2005 /****************************************************************
2006  * VGA int 10 handler
2007  ****************************************************************/
2008
2009 static void
2010 handle_1000(struct bregs *regs)
2011 {
2012     // XXX - inline
2013     biosfn_set_video_mode(regs->al);
2014     switch(regs->al & 0x7F) {
2015     case 6:
2016         regs->al = 0x3F;
2017         break;
2018     case 0:
2019     case 1:
2020     case 2:
2021     case 3:
2022     case 4:
2023     case 5:
2024     case 7:
2025         regs->al = 0x30;
2026         break;
2027     default:
2028         regs->al = 0x20;
2029     }
2030 }
2031
2032 static void
2033 handle_1001(struct bregs *regs)
2034 {
2035     biosfn_set_cursor_shape(regs->ch, regs->cl);
2036 }
2037
2038 static void
2039 handle_1002(struct bregs *regs)
2040 {
2041     biosfn_set_cursor_pos(regs->bh, regs->dx);
2042 }
2043
2044 static void
2045 handle_1003(struct bregs *regs)
2046 {
2047     biosfn_get_cursor_pos(regs->bh, &regs->cx, &regs->dx);
2048 }
2049
2050 // Read light pen pos (unimplemented)
2051 static void
2052 handle_1004(struct bregs *regs)
2053 {
2054     debug_stub(regs);
2055     regs->ax = regs->bx = regs->cx = regs->dx = 0;
2056 }
2057
2058 static void
2059 handle_1005(struct bregs *regs)
2060 {
2061     biosfn_set_active_page(regs->al);
2062 }
2063
2064 static void
2065 handle_1006(struct bregs *regs)
2066 {
2067     biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
2068                   , 0xFF, SCROLL_UP);
2069 }
2070
2071 static void
2072 handle_1007(struct bregs *regs)
2073 {
2074     biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
2075                   , 0xFF, SCROLL_DOWN);
2076 }
2077
2078 static void
2079 handle_1008(struct bregs *regs)
2080 {
2081     // XXX - inline
2082     biosfn_read_char_attr(regs->bh, &regs->ax);
2083 }
2084
2085 static void
2086 handle_1009(struct bregs *regs)
2087 {
2088     // XXX - inline
2089     biosfn_write_char_attr(regs->al, regs->bh, regs->bl, regs->cx);
2090 }
2091
2092 static void
2093 handle_100a(struct bregs *regs)
2094 {
2095     // XXX - inline
2096     biosfn_write_char_only(regs->al, regs->bh, regs->bl, regs->cx);
2097 }
2098
2099
2100 static void
2101 handle_100b00(struct bregs *regs)
2102 {
2103     // XXX - inline
2104     biosfn_set_border_color(regs);
2105 }
2106
2107 static void
2108 handle_100b01(struct bregs *regs)
2109 {
2110     // XXX - inline
2111     biosfn_set_palette(regs);
2112 }
2113
2114 static void
2115 handle_100bXX(struct bregs *regs)
2116 {
2117     debug_stub(regs);
2118 }
2119
2120 static void
2121 handle_100b(struct bregs *regs)
2122 {
2123     switch (regs->bh) {
2124     case 0x00: handle_100b00(regs); break;
2125     case 0x01: handle_100b01(regs); break;
2126     default:   handle_100bXX(regs); break;
2127     }
2128 }
2129
2130
2131 static void
2132 handle_100c(struct bregs *regs)
2133 {
2134     // XXX - inline
2135     biosfn_write_pixel(regs->bh, regs->al, regs->cx, regs->dx);
2136 }
2137
2138 static void
2139 handle_100d(struct bregs *regs)
2140 {
2141     // XXX - inline
2142     biosfn_read_pixel(regs->bh, regs->cx, regs->dx, &regs->ax);
2143 }
2144
2145 static void
2146 handle_100e(struct bregs *regs)
2147 {
2148     // Ralf Brown Interrupt list is WRONG on bh(page)
2149     // We do output only on the current page !
2150     biosfn_write_teletype(regs->al, 0xff, regs->bl, NO_ATTR);
2151 }
2152
2153 static void
2154 handle_100f(struct bregs *regs)
2155 {
2156     // XXX - inline
2157     biosfn_get_video_mode(regs);
2158 }
2159
2160
2161 static void
2162 handle_101000(struct bregs *regs)
2163 {
2164     if (regs->bl > 0x14)
2165         return;
2166     biosfn_set_single_palette_reg(regs->bl, regs->bh);
2167 }
2168
2169 static void
2170 handle_101001(struct bregs *regs)
2171 {
2172     // XXX - inline
2173     biosfn_set_overscan_border_color(regs);
2174 }
2175
2176 static void
2177 handle_101002(struct bregs *regs)
2178 {
2179     // XXX - inline
2180     biosfn_set_all_palette_reg(regs);
2181 }
2182
2183 static void
2184 handle_101003(struct bregs *regs)
2185 {
2186     // XXX - inline
2187     biosfn_toggle_intensity(regs);
2188 }
2189
2190 static void
2191 handle_101007(struct bregs *regs)
2192 {
2193     if (regs->bl > 0x14)
2194         return;
2195     regs->bh = biosfn_get_single_palette_reg(regs->bl);
2196 }
2197
2198 static void
2199 handle_101008(struct bregs *regs)
2200 {
2201     // XXX - inline
2202     biosfn_read_overscan_border_color(regs);
2203 }
2204
2205 static void
2206 handle_101009(struct bregs *regs)
2207 {
2208     // XXX - inline
2209     biosfn_get_all_palette_reg(regs);
2210 }
2211
2212 static void
2213 handle_101010(struct bregs *regs)
2214 {
2215     // XXX - inline
2216     biosfn_set_single_dac_reg(regs);
2217 }
2218
2219 static void
2220 handle_101012(struct bregs *regs)
2221 {
2222     // XXX - inline
2223     biosfn_set_all_dac_reg(regs);
2224 }
2225
2226 static void
2227 handle_101013(struct bregs *regs)
2228 {
2229     // XXX - inline
2230     biosfn_select_video_dac_color_page(regs);
2231 }
2232
2233 static void
2234 handle_101015(struct bregs *regs)
2235 {
2236     // XXX - inline
2237     biosfn_read_single_dac_reg(regs);
2238 }
2239
2240 static void
2241 handle_101017(struct bregs *regs)
2242 {
2243     // XXX - inline
2244     biosfn_read_all_dac_reg(regs);
2245 }
2246
2247 static void
2248 handle_101018(struct bregs *regs)
2249 {
2250     // XXX - inline
2251     biosfn_set_pel_mask(regs);
2252 }
2253
2254 static void
2255 handle_101019(struct bregs *regs)
2256 {
2257     // XXX - inline
2258     biosfn_read_pel_mask(regs);
2259 }
2260
2261 static void
2262 handle_10101a(struct bregs *regs)
2263 {
2264     // XXX - inline
2265     biosfn_read_video_dac_state(regs);
2266 }
2267
2268 static void
2269 handle_10101b(struct bregs *regs)
2270 {
2271     biosfn_perform_gray_scale_summing(regs->bx, regs->cx);
2272 }
2273
2274 static void
2275 handle_1010XX(struct bregs *regs)
2276 {
2277     debug_stub(regs);
2278 }
2279
2280 static void
2281 handle_1010(struct bregs *regs)
2282 {
2283     switch (regs->al) {
2284     case 0x00: handle_101000(regs); break;
2285     case 0x01: handle_101001(regs); break;
2286     case 0x02: handle_101002(regs); break;
2287     case 0x03: handle_101003(regs); break;
2288     case 0x07: handle_101007(regs); break;
2289     case 0x08: handle_101008(regs); break;
2290     case 0x09: handle_101009(regs); break;
2291     case 0x10: handle_101010(regs); break;
2292     case 0x12: handle_101012(regs); break;
2293     case 0x13: handle_101013(regs); break;
2294     case 0x15: handle_101015(regs); break;
2295     case 0x17: handle_101017(regs); break;
2296     case 0x18: handle_101018(regs); break;
2297     case 0x19: handle_101019(regs); break;
2298     case 0x1a: handle_10101a(regs); break;
2299     case 0x1b: handle_10101b(regs); break;
2300     default:   handle_1010XX(regs); break;
2301     }
2302 }
2303
2304
2305 static void
2306 handle_101100(struct bregs *regs)
2307 {
2308     // XXX - inline
2309     biosfn_load_text_user_pat(regs->al, regs->es, 0 // XXX - regs->bp
2310                               , regs->cx, regs->dx, regs->bl, regs->bh);
2311 }
2312
2313 static void
2314 handle_101101(struct bregs *regs)
2315 {
2316     // XXX - inline
2317     biosfn_load_text_8_14_pat(regs->al, regs->bl);
2318 }
2319
2320 static void
2321 handle_101102(struct bregs *regs)
2322 {
2323     // XXX - inline
2324     biosfn_load_text_8_8_pat(regs->al, regs->bl);
2325 }
2326
2327 static void
2328 handle_101103(struct bregs *regs)
2329 {
2330     // XXX - inline
2331     biosfn_set_text_block_specifier(regs);
2332 }
2333
2334 static void
2335 handle_101104(struct bregs *regs)
2336 {
2337     // XXX - inline
2338     biosfn_load_text_8_16_pat(regs->al, regs->bl);
2339 }
2340
2341 static void
2342 handle_101110(struct bregs *regs)
2343 {
2344     handle_101100(regs);
2345 }
2346
2347 static void
2348 handle_101111(struct bregs *regs)
2349 {
2350     handle_101101(regs);
2351 }
2352
2353 static void
2354 handle_101112(struct bregs *regs)
2355 {
2356     handle_101102(regs);
2357 }
2358
2359 static void
2360 handle_101114(struct bregs *regs)
2361 {
2362     handle_101104(regs);
2363 }
2364
2365 static void
2366 handle_101130(struct bregs *regs)
2367 {
2368     // XXX - inline
2369     biosfn_get_font_info(regs->bh, &regs->es, 0 // &regs->bp
2370                          , &regs->cx, &regs->dx);
2371 }
2372
2373 static void
2374 handle_1011XX(struct bregs *regs)
2375 {
2376     debug_stub(regs);
2377 }
2378
2379 static void
2380 handle_1011(struct bregs *regs)
2381 {
2382     switch (regs->al) {
2383     case 0x00: handle_101100(regs); break;
2384     case 0x01: handle_101101(regs); break;
2385     case 0x02: handle_101102(regs); break;
2386     case 0x03: handle_101103(regs); break;
2387     case 0x04: handle_101104(regs); break;
2388     case 0x10: handle_101110(regs); break;
2389     case 0x11: handle_101111(regs); break;
2390     case 0x12: handle_101112(regs); break;
2391     case 0x14: handle_101114(regs); break;
2392     case 0x30: handle_101130(regs); break;
2393     default:   handle_1011XX(regs); break;
2394     }
2395 }
2396
2397
2398 static void
2399 handle_101210(struct bregs *regs)
2400 {
2401     // XXX - inline
2402     biosfn_get_ega_info(regs);
2403 }
2404
2405 static void
2406 handle_101230(struct bregs *regs)
2407 {
2408     // XXX - inline
2409     biosfn_select_vert_res(regs);
2410 }
2411
2412 static void
2413 handle_101231(struct bregs *regs)
2414 {
2415     // XXX - inline
2416     biosfn_enable_default_palette_loading(regs);
2417 }
2418
2419 static void
2420 handle_101232(struct bregs *regs)
2421 {
2422     // XXX - inline
2423     biosfn_enable_video_addressing(regs);
2424 }
2425
2426 static void
2427 handle_101233(struct bregs *regs)
2428 {
2429     // XXX - inline
2430     biosfn_enable_grayscale_summing(regs);
2431 }
2432
2433 static void
2434 handle_101234(struct bregs *regs)
2435 {
2436     // XXX - inline
2437     biosfn_enable_cursor_emulation(regs);
2438 }
2439
2440 static void
2441 handle_101235(struct bregs *regs)
2442 {
2443     debug_stub(regs);
2444     regs->al = 0x12;
2445 }
2446
2447 static void
2448 handle_101236(struct bregs *regs)
2449 {
2450     debug_stub(regs);
2451     regs->al = 0x12;
2452 }
2453
2454 static void
2455 handle_1012XX(struct bregs *regs)
2456 {
2457     debug_stub(regs);
2458 }
2459
2460 static void
2461 handle_1012(struct bregs *regs)
2462 {
2463     switch (regs->bl) {
2464     case 0x10: handle_101210(regs); break;
2465     case 0x30: handle_101230(regs); break;
2466     case 0x31: handle_101231(regs); break;
2467     case 0x32: handle_101232(regs); break;
2468     case 0x33: handle_101233(regs); break;
2469     case 0x34: handle_101234(regs); break;
2470     case 0x35: handle_101235(regs); break;
2471     case 0x36: handle_101236(regs); break;
2472     default:   handle_1012XX(regs); break;
2473     }
2474
2475     // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
2476 }
2477
2478
2479 static void
2480 handle_1013(struct bregs *regs)
2481 {
2482     // XXX - inline
2483     biosfn_write_string(regs->al, regs->bh, regs->bl, regs->cx
2484                         , regs->dh, regs->dl, regs->es, 0); // regs->bp);
2485 }
2486
2487
2488 static void
2489 handle_101a00(struct bregs *regs)
2490 {
2491     // XXX - inline
2492     biosfn_read_display_code(regs);
2493 }
2494
2495 static void
2496 handle_101a01(struct bregs *regs)
2497 {
2498     // XXX - inline
2499     biosfn_set_display_code(regs);
2500 }
2501
2502 static void
2503 handle_101aXX(struct bregs *regs)
2504 {
2505     debug_stub(regs);
2506 }
2507
2508 static void
2509 handle_101a(struct bregs *regs)
2510 {
2511     switch (regs->al) {
2512     case 0x00: handle_101a00(regs); break;
2513     case 0x01: handle_101a01(regs); break;
2514     default:   handle_101aXX(regs); break;
2515     }
2516 }
2517
2518
2519 static void
2520 handle_101b(struct bregs *regs)
2521 {
2522     // XXX - inline
2523     biosfn_read_state_info(regs->bx, regs->es, regs->di);
2524     regs->al = 0x1B;
2525 }
2526
2527
2528 static void
2529 handle_101c00(struct bregs *regs)
2530 {
2531     // XXX - inline
2532     regs->bx = biosfn_read_video_state_size(regs->cx);
2533 }
2534
2535 static void
2536 handle_101c01(struct bregs *regs)
2537 {
2538     // XXX - inline
2539     biosfn_save_video_state(regs->cx, regs->es, regs->bx);
2540 }
2541
2542 static void
2543 handle_101c02(struct bregs *regs)
2544 {
2545     // XXX - inline
2546     biosfn_restore_video_state(regs->cx, regs->es, regs->bx);
2547 }
2548
2549 static void
2550 handle_101cXX(struct bregs *regs)
2551 {
2552     debug_stub(regs);
2553 }
2554
2555 static void
2556 handle_101c(struct bregs *regs)
2557 {
2558     switch (regs->al) {
2559     case 0x00: handle_101c00(regs); break;
2560     case 0x01: handle_101c01(regs); break;
2561     case 0x02: handle_101c02(regs); break;
2562     default:   handle_101cXX(regs); break;
2563     }
2564 }
2565
2566
2567 static void
2568 handle_104f00(struct bregs *regs)
2569 {
2570     // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
2571     // XXX - OR cirrus_vesa_00h
2572 }
2573
2574 static void
2575 handle_104f01(struct bregs *regs)
2576 {
2577     // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
2578     // XXX - OR cirrus_vesa_01h
2579 }
2580
2581 static void
2582 handle_104f02(struct bregs *regs)
2583 {
2584     // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
2585     // XXX - OR cirrus_vesa_02h
2586 }
2587
2588 static void
2589 handle_104f03(struct bregs *regs)
2590 {
2591     // XXX - vbe_biosfn_return_current_mode
2592     // XXX - OR cirrus_vesa_03h
2593 }
2594
2595 static void
2596 handle_104f04(struct bregs *regs)
2597 {
2598     // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
2599 }
2600
2601 static void
2602 handle_104f05(struct bregs *regs)
2603 {
2604     // XXX - vbe_biosfn_display_window_control
2605     // XXX - OR cirrus_vesa_05h
2606 }
2607
2608 static void
2609 handle_104f06(struct bregs *regs)
2610 {
2611     // XXX - vbe_biosfn_set_get_logical_scan_line_length
2612     // XXX - OR cirrus_vesa_06h
2613 }
2614
2615 static void
2616 handle_104f07(struct bregs *regs)
2617 {
2618     // XXX - vbe_biosfn_set_get_display_start
2619     // XXX - OR cirrus_vesa_07h
2620 }
2621
2622 static void
2623 handle_104f08(struct bregs *regs)
2624 {
2625     // XXX - vbe_biosfn_set_get_dac_palette_format
2626 }
2627
2628 static void
2629 handle_104f0a(struct bregs *regs)
2630 {
2631     // XXX - vbe_biosfn_return_protected_mode_interface
2632 }
2633
2634 static void
2635 handle_104fXX(struct bregs *regs)
2636 {
2637     debug_stub(regs);
2638     regs->ax = 0x0100;
2639 }
2640
2641 static void
2642 handle_104f(struct bregs *regs)
2643 {
2644     if (! CONFIG_VBE) {
2645         handle_104fXX(regs);
2646         return;
2647     }
2648
2649     // XXX - check vbe_has_vbe_display()?
2650
2651     switch (regs->al) {
2652     case 0x00: handle_104f00(regs); break;
2653     case 0x01: handle_104f01(regs); break;
2654     case 0x02: handle_104f02(regs); break;
2655     case 0x03: handle_104f03(regs); break;
2656     case 0x04: handle_104f04(regs); break;
2657     case 0x05: handle_104f05(regs); break;
2658     case 0x06: handle_104f06(regs); break;
2659     case 0x07: handle_104f07(regs); break;
2660     case 0x08: handle_104f08(regs); break;
2661     case 0x0a: handle_104f0a(regs); break;
2662     default:   handle_104fXX(regs); break;
2663     }
2664 }
2665
2666
2667 static void
2668 handle_10XX(struct bregs *regs)
2669 {
2670     debug_stub(regs);
2671 }
2672
2673 // INT 10h Video Support Service Entry Point
2674 void VISIBLE16
2675 handle_10(struct bregs *regs)
2676 {
2677     debug_enter(regs, DEBUG_VGA_10);
2678     switch (regs->ah) {
2679     case 0x00: handle_1000(regs); break;
2680     case 0x01: handle_1001(regs); break;
2681     case 0x02: handle_1002(regs); break;
2682     case 0x03: handle_1003(regs); break;
2683     case 0x04: handle_1004(regs); break;
2684     case 0x05: handle_1005(regs); break;
2685     case 0x06: handle_1006(regs); break;
2686     case 0x07: handle_1007(regs); break;
2687     case 0x08: handle_1008(regs); break;
2688     case 0x09: handle_1009(regs); break;
2689     case 0x0a: handle_100a(regs); break;
2690     case 0x0b: handle_100b(regs); break;
2691     case 0x0c: handle_100c(regs); break;
2692     case 0x0d: handle_100d(regs); break;
2693     case 0x0e: handle_100e(regs); break;
2694     case 0x0f: handle_100f(regs); break;
2695     case 0x10: handle_1010(regs); break;
2696     case 0x11: handle_1011(regs); break;
2697     case 0x12: handle_1012(regs); break;
2698     case 0x13: handle_1013(regs); break;
2699     case 0x1a: handle_101a(regs); break;
2700     case 0x1b: handle_101b(regs); break;
2701     case 0x1c: handle_101c(regs); break;
2702     case 0x4f: handle_104f(regs); break;
2703     default:   handle_10XX(regs); break;
2704     }
2705 }
2706
2707
2708 /****************************************************************
2709  * VGA post
2710  ****************************************************************/
2711
2712 static void
2713 init_bios_area()
2714 {
2715     // init detected hardware BIOS Area
2716     // set 80x25 color (not clear from RBIL but usual)
2717     u16 eqf = GET_BDA(equipment_list_flags);
2718     SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
2719
2720     // Just for the first int10 find its children
2721
2722     // the default char height
2723     SET_BDA(char_height, 0x10);
2724
2725     // Clear the screen
2726     SET_BDA(video_ctl, 0x60);
2727
2728     // Set the basic screen we have
2729     SET_BDA(video_switches, 0xf9);
2730
2731     // Set the basic modeset options
2732     SET_BDA(modeset_ctl, 0x51);
2733
2734     // Set the  default MSR
2735     SET_BDA(video_msr, 0x09);
2736 }
2737
2738 static void
2739 init_vga_card()
2740 {
2741     // switch to color mode and enable CPU access 480 lines
2742     outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
2743     // more than 64k 3C4/04
2744     outb(0x04, VGAREG_SEQU_ADDRESS);
2745     outb(0x02, VGAREG_SEQU_DATA);
2746 }
2747
2748 void VISIBLE16
2749 vga_post(struct bregs *regs)
2750 {
2751     debug_enter(regs, DEBUG_VGA_POST);
2752
2753     init_vga_card();
2754
2755     init_bios_area();
2756
2757     // vbe_init();
2758
2759     extern void entry_10(void);
2760     SET_IVT(0x10, 0xC000, (u32)entry_10);
2761
2762     if (CONFIG_CIRRUS)
2763         cirrus_init();
2764
2765     // XXX - clear screen and display info
2766
2767     // XXX: fill it
2768     SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
2769     SET_VGA(video_save_pointer_table[1], 0xC000);
2770
2771     // Fixup checksum
2772     extern u8 _rom_header_size, _rom_header_checksum;
2773     SET_VGA(_rom_header_checksum, 0);
2774     u8 sum = -checksum_far(0xC000, 0, _rom_header_size * 512);
2775     SET_VGA(_rom_header_checksum, sum);
2776 }