VGA: Extract code from vga.c into new files vgaio.c and vgafb.c.
[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 //  * define structs for save/restore state
11 //  * review correctness of converted asm by comparing with RBIL
12 //  * refactor redundant code into sub-functions
13 //  * See if there is a method to the in/out stuff that can be encapsulated.
14 //  * remove "biosfn" prefixes
15 //  * verify all funcs static
16 //
17 //  * convert vbe/clext code
18 //
19 //  * separate code into separate files
20 //  * extract hw code from bios interfaces
21
22 #include "bregs.h" // struct bregs
23 #include "biosvar.h" // GET_BDA
24 #include "util.h" // memset
25 #include "vgatables.h" // find_vga_entry
26
27 // XXX
28 #define CONFIG_VBE 0
29 #define CONFIG_CIRRUS 0
30
31 // XXX
32 #define DEBUG_VGA_POST 1
33 #define DEBUG_VGA_10 3
34
35 #define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
36
37
38 // ===================================================================
39 //
40 // Video Utils
41 //
42 // ===================================================================
43
44 // -------------------------------------------------------------------
45 inline void
46 call16_vgaint(u32 eax, u32 ebx)
47 {
48     asm volatile(
49         "int $0x10\n"
50         "cli\n"
51         "cld"
52         :
53         : "a"(eax), "b"(ebx)
54         : "cc", "memory");
55 }
56
57
58 // ===================================================================
59 //
60 // BIOS functions
61 //
62 // ===================================================================
63
64 // -------------------------------------------------------------------
65 static void
66 biosfn_perform_gray_scale_summing(u16 start, u16 count)
67 {
68     inb(VGAREG_ACTL_RESET);
69     outb(0x00, VGAREG_ACTL_ADDRESS);
70
71     int i;
72     for (i = start; i < start+count; i++) {
73         // set read address and switch to read mode
74         outb(i, VGAREG_DAC_READ_ADDRESS);
75         // get 6-bit wide RGB data values
76         u8 r = inb(VGAREG_DAC_DATA);
77         u8 g = inb(VGAREG_DAC_DATA);
78         u8 b = inb(VGAREG_DAC_DATA);
79
80         // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
81         u16 intensity = ((77 * r + 151 * g + 28 * b) + 0x80) >> 8;
82
83         if (intensity > 0x3f)
84             intensity = 0x3f;
85
86         // set write address and switch to write mode
87         outb(i, VGAREG_DAC_WRITE_ADDRESS);
88         // write new intensity value
89         outb(intensity & 0xff, VGAREG_DAC_DATA);
90         outb(intensity & 0xff, VGAREG_DAC_DATA);
91         outb(intensity & 0xff, VGAREG_DAC_DATA);
92     }
93     inb(VGAREG_ACTL_RESET);
94     outb(0x20, VGAREG_ACTL_ADDRESS);
95 }
96
97 // -------------------------------------------------------------------
98 static void
99 biosfn_set_cursor_shape(u8 CH, u8 CL)
100 {
101     CH &= 0x3f;
102     CL &= 0x1f;
103
104     u16 curs = (CH << 8) + CL;
105     SET_BDA(cursor_type, curs);
106
107     u8 modeset_ctl = GET_BDA(modeset_ctl);
108     u16 cheight = GET_BDA(char_height);
109     if ((modeset_ctl & 0x01) && (cheight > 8) && (CL < 8) && (CH < 0x20)) {
110         if (CL != (CH + 1))
111             CH = ((CH + 1) * cheight / 8) - 1;
112         else
113             CH = ((CL + 1) * cheight / 8) - 2;
114         CL = ((CL + 1) * cheight / 8) - 1;
115     }
116     // CTRC regs 0x0a and 0x0b
117     u16 crtc_addr = GET_BDA(crtc_address);
118     outb(0x0a, crtc_addr);
119     outb(CH, crtc_addr + 1);
120     outb(0x0b, crtc_addr);
121     outb(CL, crtc_addr + 1);
122 }
123
124 static u16
125 biosfn_get_cursor_shape(u8 page)
126 {
127     if (page > 7)
128         return 0;
129     // FIXME should handle VGA 14/16 lines
130     return GET_BDA(cursor_type);
131 }
132
133 // -------------------------------------------------------------------
134 static void
135 biosfn_set_cursor_pos(u8 page, u16 cursor)
136 {
137     // Should not happen...
138     if (page > 7)
139         return;
140
141     // Bios cursor pos
142     SET_BDA(cursor_pos[page], cursor);
143
144     // Set the hardware cursor
145     u8 current = GET_BDA(video_page);
146     if (page != current)
147         return;
148
149     // Get the dimensions
150     u16 nbcols = GET_BDA(video_cols);
151     u16 nbrows = GET_BDA(video_rows) + 1;
152
153     u8 xcurs = cursor & 0x00ff;
154     u8 ycurs = (cursor & 0xff00) >> 8;
155
156     // Calculate the address knowing nbcols nbrows and page num
157     u16 address = SCREEN_IO_START(nbcols, nbrows, page) + xcurs + ycurs * nbcols;
158
159     // CRTC regs 0x0e and 0x0f
160     u16 crtc_addr = GET_BDA(crtc_address);
161     outb(0x0e, crtc_addr);
162     outb((address & 0xff00) >> 8, crtc_addr + 1);
163     outb(0x0f, crtc_addr);
164     outb(address & 0x00ff, crtc_addr + 1);
165 }
166
167 u16
168 biosfn_get_cursor_pos(u8 page)
169 {
170     if (page > 7)
171         return 0;
172     // FIXME should handle VGA 14/16 lines
173     return GET_BDA(cursor_pos[page]);
174 }
175
176 // -------------------------------------------------------------------
177 static void
178 biosfn_set_active_page(u8 page)
179 {
180     if (page > 7)
181         return;
182
183     // Get the mode
184     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
185     if (!vmode_g)
186         return;
187
188     // Get pos curs pos for the right page
189     u16 cursor = biosfn_get_cursor_pos(page);
190
191     u16 address;
192     if (GET_GLOBAL(vmode_g->class) == TEXT) {
193         // Get the dimensions
194         u16 nbcols = GET_BDA(video_cols);
195         u16 nbrows = GET_BDA(video_rows) + 1;
196
197         // Calculate the address knowing nbcols nbrows and page num
198         address = SCREEN_MEM_START(nbcols, nbrows, page);
199         SET_BDA(video_pagestart, address);
200
201         // Start address
202         address = SCREEN_IO_START(nbcols, nbrows, page);
203     } else {
204         struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
205         address = page * GET_GLOBAL(vparam_g->slength);
206     }
207
208     // CRTC regs 0x0c and 0x0d
209     u16 crtc_addr = GET_BDA(crtc_address);
210     outb(0x0c, crtc_addr);
211     outb((address & 0xff00) >> 8, crtc_addr + 1);
212     outb(0x0d, crtc_addr);
213     outb(address & 0x00ff, crtc_addr + 1);
214
215     // And change the BIOS page
216     SET_BDA(video_page, page);
217
218     dprintf(1, "Set active page %02x address %04x\n", page, address);
219
220     // Display the cursor, now the page is active
221     biosfn_set_cursor_pos(page, cursor);
222 }
223
224 static void
225 biosfn_set_video_mode(u8 mode)
226 {                               // mode: Bit 7 is 1 if no clear screen
227     if (CONFIG_CIRRUS)
228         cirrus_set_video_mode(mode);
229
230     if (CONFIG_VBE)
231         if (vbe_has_vbe_display())
232             dispi_set_enable(VBE_DISPI_DISABLED);
233
234     // The real mode
235     u8 noclearmem = mode & 0x80;
236     mode = mode & 0x7f;
237
238     // find the entry in the video modes
239     struct vgamode_s *vmode_g = find_vga_entry(mode);
240     dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
241     if (!vmode_g)
242         return;
243
244     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
245     u16 twidth = GET_GLOBAL(vparam_g->twidth);
246     u16 theightm1 = GET_GLOBAL(vparam_g->theightm1);
247     u16 cheight = GET_GLOBAL(vparam_g->cheight);
248
249     // Read the bios mode set control
250     u8 modeset_ctl = GET_BDA(modeset_ctl);
251
252     // Then we know the number of lines
253 // FIXME
254
255     // if palette loading (bit 3 of modeset ctl = 0)
256     if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
257         outb(GET_GLOBAL(vmode_g->pelmask), VGAREG_PEL_MASK);
258
259         // Set the whole dac always, from 0
260         outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
261
262         // From which palette
263         u8 *palette_g = GET_GLOBAL(vmode_g->dac);
264         u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
265         // Always 256*3 values
266         u16 i;
267         for (i = 0; i < 0x0100; i++) {
268             if (i < palsize) {
269                 outb(GET_GLOBAL(palette_g[(i * 3) + 0]), VGAREG_DAC_DATA);
270                 outb(GET_GLOBAL(palette_g[(i * 3) + 1]), VGAREG_DAC_DATA);
271                 outb(GET_GLOBAL(palette_g[(i * 3) + 2]), VGAREG_DAC_DATA);
272             } else {
273                 outb(0, VGAREG_DAC_DATA);
274                 outb(0, VGAREG_DAC_DATA);
275                 outb(0, VGAREG_DAC_DATA);
276             }
277         }
278         if ((modeset_ctl & 0x02) == 0x02)
279             biosfn_perform_gray_scale_summing(0x00, 0x100);
280     }
281     // Reset Attribute Ctl flip-flop
282     inb(VGAREG_ACTL_RESET);
283
284     // Set Attribute Ctl
285     u16 i;
286     for (i = 0; i <= 0x13; i++) {
287         outb(i, VGAREG_ACTL_ADDRESS);
288         outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
289     }
290     outb(0x14, VGAREG_ACTL_ADDRESS);
291     outb(0x00, VGAREG_ACTL_WRITE_DATA);
292
293     // Set Sequencer Ctl
294     outb(0, VGAREG_SEQU_ADDRESS);
295     outb(0x03, VGAREG_SEQU_DATA);
296     for (i = 1; i <= 4; i++) {
297         outb(i, VGAREG_SEQU_ADDRESS);
298         outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
299     }
300
301     // Set Grafx Ctl
302     for (i = 0; i <= 8; i++) {
303         outb(i, VGAREG_GRDC_ADDRESS);
304         outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
305     }
306
307     // Set CRTC address VGA or MDA
308     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
309     if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
310         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
311
312     // Disable CRTC write protection
313     outw(0x0011, crtc_addr);
314     // Set CRTC regs
315     for (i = 0; i <= 0x18; i++) {
316         outb(i, crtc_addr);
317         outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
318     }
319
320     // Set the misc register
321     outb(GET_GLOBAL(vparam_g->miscreg), VGAREG_WRITE_MISC_OUTPUT);
322
323     // Enable video
324     outb(0x20, VGAREG_ACTL_ADDRESS);
325     inb(VGAREG_ACTL_RESET);
326
327     if (noclearmem == 0x00) {
328         if (GET_GLOBAL(vmode_g->class) == TEXT) {
329             memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
330         } else {
331             if (mode < 0x0d) {
332                 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
333             } else {
334                 outb(0x02, VGAREG_SEQU_ADDRESS);
335                 u8 mmask = inb(VGAREG_SEQU_DATA);
336                 outb(0x0f, VGAREG_SEQU_DATA);   // all planes
337                 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
338                 outb(mmask, VGAREG_SEQU_DATA);
339             }
340         }
341     }
342     // Set the BIOS mem
343     SET_BDA(video_mode, mode);
344     SET_BDA(video_cols, twidth);
345     SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
346     SET_BDA(crtc_address, crtc_addr);
347     SET_BDA(video_rows, theightm1);
348     SET_BDA(char_height, cheight);
349     SET_BDA(video_ctl, (0x60 | noclearmem));
350     SET_BDA(video_switches, 0xF9);
351     SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
352
353     // FIXME We nearly have the good tables. to be reworked
354     SET_BDA(dcc_index, 0x08);   // 8 is VGA should be ok for now
355     SET_BDA(video_savetable_ptr, (u32)video_save_pointer_table);
356     SET_BDA(video_savetable_seg, get_global_seg());
357
358     // FIXME
359     SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
360     SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
361
362     // Set cursor shape
363     if (GET_GLOBAL(vmode_g->class) == TEXT)
364         biosfn_set_cursor_shape(0x06, 0x07);
365     // Set cursor pos for page 0..7
366     for (i = 0; i < 8; i++)
367         biosfn_set_cursor_pos(i, 0x0000);
368
369     // Set active page 0
370     biosfn_set_active_page(0x00);
371
372     // Write the fonts in memory
373     if (GET_GLOBAL(vmode_g->class) == TEXT) {
374         call16_vgaint(0x1104, 0);
375         call16_vgaint(0x1103, 0);
376     }
377     // Set the ints 0x1F and 0x43
378     SET_IVT(0x1f, get_global_seg(), (u32)&vgafont8[128 * 8]);
379
380     switch (cheight) {
381     case 8:
382         SET_IVT(0x43, get_global_seg(), (u32)vgafont8);
383         break;
384     case 14:
385         SET_IVT(0x43, get_global_seg(), (u32)vgafont14);
386         break;
387     case 16:
388         SET_IVT(0x43, get_global_seg(), (u32)vgafont16);
389         break;
390     }
391 }
392
393 // -------------------------------------------------------------------
394 static void
395 biosfn_write_teletype(u8 car, u8 page, u8 attr, u8 flag)
396 {                               // flag = WITH_ATTR / NO_ATTR
397     // special case if page is 0xff, use current page
398     if (page == 0xff)
399         page = GET_BDA(video_page);
400
401     // Get the mode
402     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
403     if (!vmode_g)
404         return;
405
406     // Get the cursor pos for the page
407     u16 cursor = biosfn_get_cursor_pos(page);
408     u8 xcurs = cursor & 0x00ff;
409     u8 ycurs = (cursor & 0xff00) >> 8;
410
411     // Get the dimensions
412     u16 nbrows = GET_BDA(video_rows) + 1;
413     u16 nbcols = GET_BDA(video_cols);
414
415     switch (car) {
416     case 7:
417         //FIXME should beep
418         break;
419
420     case 8:
421         if (xcurs > 0)
422             xcurs--;
423         break;
424
425     case '\r':
426         xcurs = 0;
427         break;
428
429     case '\n':
430         ycurs++;
431         break;
432
433     case '\t':
434         do {
435             biosfn_write_teletype(' ', page, attr, flag);
436             cursor = biosfn_get_cursor_pos(page);
437             xcurs = cursor & 0x00ff;
438             ycurs = (cursor & 0xff00) >> 8;
439         } while (xcurs % 8 == 0);
440         break;
441
442     default:
443         if (flag == WITH_ATTR)
444             biosfn_write_char_attr(car, page, attr, 1);
445         else
446             biosfn_write_char_only(car, page, attr, 1);
447         xcurs++;
448     }
449
450     // Do we need to wrap ?
451     if (xcurs == nbcols) {
452         xcurs = 0;
453         ycurs++;
454     }
455     // Do we need to scroll ?
456     if (ycurs == nbrows) {
457         if (GET_GLOBAL(vmode_g->class) == TEXT)
458             biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, page,
459                           SCROLL_UP);
460         else
461             biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, page,
462                           SCROLL_UP);
463         ycurs -= 1;
464     }
465     // Set the cursor for the page
466     cursor = ycurs;
467     cursor <<= 8;
468     cursor += xcurs;
469     biosfn_set_cursor_pos(page, cursor);
470 }
471
472 // -------------------------------------------------------------------
473 static void
474 biosfn_get_video_mode(struct bregs *regs)
475 {
476     regs->bh = GET_BDA(video_page);
477     regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
478     regs->ah = GET_BDA(video_cols);
479 }
480
481 static void
482 set_scan_lines(u8 lines)
483 {
484     u16 crtc_addr = GET_BDA(crtc_address);
485     outb(0x09, crtc_addr);
486     u8 crtc_r9 = inb(crtc_addr + 1);
487     crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
488     outb(crtc_r9, crtc_addr + 1);
489     if (lines == 8)
490         biosfn_set_cursor_shape(0x06, 0x07);
491     else
492         biosfn_set_cursor_shape(lines - 4, lines - 3);
493     SET_BDA(char_height, lines);
494     outb(0x12, crtc_addr);
495     u16 vde = inb(crtc_addr + 1);
496     outb(0x07, crtc_addr);
497     u8 ovl = inb(crtc_addr + 1);
498     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
499     u8 rows = vde / lines;
500     SET_BDA(video_rows, rows - 1);
501     u16 cols = GET_BDA(video_cols);
502     SET_BDA(video_pagesize, rows * cols * 2);
503 }
504
505 // -------------------------------------------------------------------
506 static void
507 biosfn_get_font_info(u8 BH, u16 *ES, u16 *BP, u16 *CX, u16 *DX)
508 {
509     switch (BH) {
510     case 0x00: {
511         u32 segoff = GET_IVT(0x1f).segoff;
512         *ES = segoff >> 16;
513         *BP = segoff;
514         break;
515     }
516     case 0x01: {
517         u32 segoff = GET_IVT(0x43).segoff;
518         *ES = segoff >> 16;
519         *BP = segoff;
520         break;
521     }
522     case 0x02:
523         *ES = get_global_seg();
524         *BP = (u32)vgafont14;
525         break;
526     case 0x03:
527         *ES = get_global_seg();
528         *BP = (u32)vgafont8;
529         break;
530     case 0x04:
531         *ES = get_global_seg();
532         *BP = (u32)vgafont8 + 128 * 8;
533         break;
534     case 0x05:
535         *ES = get_global_seg();
536         *BP = (u32)vgafont14alt;
537         break;
538     case 0x06:
539         *ES = get_global_seg();
540         *BP = (u32)vgafont16;
541         break;
542     case 0x07:
543         *ES = get_global_seg();
544         *BP = (u32)vgafont16alt;
545         break;
546     default:
547         dprintf(1, "Get font info BH(%02x) was discarded\n", BH);
548         return;
549     }
550     // Set byte/char of on screen font
551     *CX = GET_BDA(char_height) & 0xff;
552
553     // Set Highest char row
554     *DX = GET_BDA(video_rows);
555 }
556
557 // -------------------------------------------------------------------
558 static void
559 biosfn_get_ega_info(struct bregs *regs)
560 {
561     regs->cx = GET_BDA(video_switches) & 0x0f;
562     regs->ax = GET_BDA(crtc_address);
563     if (regs->ax == VGAREG_MDA_CRTC_ADDRESS)
564         regs->bx = 0x0103;
565     else
566         regs->bx = 0x0003;
567 }
568
569 // -------------------------------------------------------------------
570 static void
571 biosfn_select_vert_res(struct bregs *regs)
572 {
573     u8 mctl = GET_BDA(modeset_ctl);
574     u8 vswt = GET_BDA(video_switches);
575
576     switch (regs->al) {
577     case 0x00:
578         // 200 lines
579         mctl = (mctl & ~0x10) | 0x80;
580         vswt = (vswt & ~0x0f) | 0x08;
581         break;
582     case 0x01:
583         // 350 lines
584         mctl &= ~0x90;
585         vswt = (vswt & ~0x0f) | 0x09;
586         break;
587     case 0x02:
588         // 400 lines
589         mctl = (mctl & ~0x80) | 0x10;
590         vswt = (vswt & ~0x0f) | 0x09;
591         break;
592     default:
593         dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
594         break;
595     }
596     SET_BDA(modeset_ctl, mctl);
597     SET_BDA(video_switches, vswt);
598     regs->ax = 0x1212;
599 }
600
601 static void
602 biosfn_enable_default_palette_loading(struct bregs *regs)
603 {
604     u8 v = (regs->al & 0x01) << 3;
605     u8 mctl = GET_BDA(video_ctl) & ~0x08;
606     SET_BDA(video_ctl, mctl | v);
607     regs->ax = 0x1212;
608 }
609
610
611 static void
612 biosfn_enable_grayscale_summing(struct bregs *regs)
613 {
614     u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
615     u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
616     SET_BDA(modeset_ctl, v | v2);
617     regs->ax = 0x1212;
618 }
619
620 static void
621 biosfn_enable_cursor_emulation(struct bregs *regs)
622 {
623     u8 v = (regs->al & 0x01) ^ 0x01;
624     u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
625     SET_BDA(modeset_ctl, v | v2);
626     regs->ax = 0x1212;
627 }
628
629 // -------------------------------------------------------------------
630 static void
631 biosfn_write_string(u8 flag, u8 page, u8 attr, u16 count, u8 row, u8 col,
632                     u16 seg, u8 *offset_far)
633 {
634     // Read curs info for the page
635     u16 oldcurs = biosfn_get_cursor_pos(page);
636
637     // if row=0xff special case : use current cursor position
638     if (row == 0xff) {
639         col = oldcurs & 0x00ff;
640         row = (oldcurs & 0xff00) >> 8;
641     }
642
643     u16 newcurs = row;
644     newcurs <<= 8;
645     newcurs += col;
646     biosfn_set_cursor_pos(page, newcurs);
647
648     while (count-- != 0) {
649         u8 car = GET_FARVAR(seg, *offset_far);
650         offset_far++;
651         if ((flag & 0x02) != 0) {
652             attr = GET_FARVAR(seg, *offset_far);
653             offset_far++;
654         }
655
656         biosfn_write_teletype(car, page, attr, WITH_ATTR);
657     }
658
659     // Set back curs pos
660     if ((flag & 0x01) == 0)
661         biosfn_set_cursor_pos(page, oldcurs);
662 }
663
664 // -------------------------------------------------------------------
665 static void
666 biosfn_read_display_code(struct bregs *regs)
667 {
668     regs->bx = GET_BDA(dcc_index);
669     regs->al = 0x1a;
670 }
671
672 static void
673 biosfn_set_display_code(struct bregs *regs)
674 {
675     SET_BDA(dcc_index, regs->bl);
676     dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
677     regs->al = 0x1a;
678 }
679
680 // -------------------------------------------------------------------
681 static void
682 biosfn_read_state_info(u16 BX, u16 ES, u16 DI)
683 {
684     // Address of static functionality table
685     SET_FARVAR(ES, *(u16*)(DI + 0x00), (u32)static_functionality);
686     SET_FARVAR(ES, *(u16*)(DI + 0x02), get_global_seg());
687
688     // Hard coded copy from BIOS area. Should it be cleaner ?
689     memcpy_far(ES, (void*)(DI + 0x04), SEG_BDA, (void*)0x49, 30);
690     memcpy_far(ES, (void*)(DI + 0x22), SEG_BDA, (void*)0x84, 3);
691
692     SET_FARVAR(ES, *(u8*)(DI + 0x25), GET_BDA(dcc_index));
693     SET_FARVAR(ES, *(u8*)(DI + 0x26), 0);
694     SET_FARVAR(ES, *(u8*)(DI + 0x27), 16);
695     SET_FARVAR(ES, *(u8*)(DI + 0x28), 0);
696     SET_FARVAR(ES, *(u8*)(DI + 0x29), 8);
697     SET_FARVAR(ES, *(u8*)(DI + 0x2a), 2);
698     SET_FARVAR(ES, *(u8*)(DI + 0x2b), 0);
699     SET_FARVAR(ES, *(u8*)(DI + 0x2c), 0);
700     SET_FARVAR(ES, *(u8*)(DI + 0x31), 3);
701     SET_FARVAR(ES, *(u8*)(DI + 0x32), 0);
702
703     memset_far(ES, (void*)(DI + 0x33), 0, 13);
704 }
705
706 // -------------------------------------------------------------------
707 // -------------------------------------------------------------------
708 static u16
709 biosfn_read_video_state_size(u16 CX)
710 {
711     u16 size = 0;
712     if (CX & 1)
713         size += 0x46;
714     if (CX & 2)
715         size += (5 + 8 + 5) * 2 + 6;
716     if (CX & 4)
717         size += 3 + 256 * 3 + 1;
718     return size;
719 }
720
721 static u16
722 biosfn_save_video_state(u16 CX, u16 ES, u16 BX)
723 {
724     u16 crtc_addr = GET_BDA(crtc_address);
725     if (CX & 1) {
726         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_ADDRESS));
727         BX++;
728         SET_FARVAR(ES, *(u8*)(BX+0), inb(crtc_addr));
729         BX++;
730         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_GRDC_ADDRESS));
731         BX++;
732         inb(VGAREG_ACTL_RESET);
733         u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
734         SET_FARVAR(ES, *(u8*)(BX+0), ar_index);
735         BX++;
736         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_READ_FEATURE_CTL));
737         BX++;
738
739         u16 i;
740         for (i = 1; i <= 4; i++) {
741             outb(i, VGAREG_SEQU_ADDRESS);
742             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_DATA));
743             BX++;
744         }
745         outb(0, VGAREG_SEQU_ADDRESS);
746         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_DATA));
747         BX++;
748
749         for (i = 0; i <= 0x18; i++) {
750             outb(i, crtc_addr);
751             SET_FARVAR(ES, *(u8*)(BX+0), inb(crtc_addr + 1));
752             BX++;
753         }
754
755         for (i = 0; i <= 0x13; i++) {
756             inb(VGAREG_ACTL_RESET);
757             outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
758             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_ACTL_READ_DATA));
759             BX++;
760         }
761         inb(VGAREG_ACTL_RESET);
762
763         for (i = 0; i <= 8; i++) {
764             outb(i, VGAREG_GRDC_ADDRESS);
765             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_GRDC_DATA));
766             BX++;
767         }
768
769         SET_FARVAR(ES, *(u16*)(BX+0), crtc_addr);
770         BX += 2;
771
772         /* XXX: read plane latches */
773         SET_FARVAR(ES, *(u8*)(BX+0), 0);
774         BX++;
775         SET_FARVAR(ES, *(u8*)(BX+0), 0);
776         BX++;
777         SET_FARVAR(ES, *(u8*)(BX+0), 0);
778         BX++;
779         SET_FARVAR(ES, *(u8*)(BX+0), 0);
780         BX++;
781     }
782     if (CX & 2) {
783         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_mode));
784         BX++;
785         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_cols));
786         BX += 2;
787         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_pagesize));
788         BX += 2;
789         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(crtc_address));
790         BX += 2;
791         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_rows));
792         BX++;
793         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(char_height));
794         BX += 2;
795         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_ctl));
796         BX++;
797         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_switches));
798         BX++;
799         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(modeset_ctl));
800         BX++;
801         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(cursor_type));
802         BX += 2;
803         u16 i;
804         for (i = 0; i < 8; i++) {
805             SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(cursor_pos[i]));
806             BX += 2;
807         }
808         SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_pagestart));
809         BX += 2;
810         SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_page));
811         BX++;
812         /* current font */
813         SET_FARVAR(ES, *(u32*)(BX+0), GET_IVT(0x1f).segoff);
814         BX += 4;
815         SET_FARVAR(ES, *(u32*)(BX+0), GET_IVT(0x43).segoff);
816         BX += 4;
817     }
818     if (CX & 4) {
819         /* XXX: check this */
820         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_STATE));
821         BX++;                   /* read/write mode dac */
822         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_WRITE_ADDRESS));
823         BX++;                   /* pix address */
824         SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_PEL_MASK));
825         BX++;
826         // Set the whole dac always, from 0
827         outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
828         u16 i;
829         for (i = 0; i < 256 * 3; i++) {
830             SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_DATA));
831             BX++;
832         }
833         SET_FARVAR(ES, *(u8*)(BX+0), 0);
834         BX++;                   /* color select register */
835     }
836     return BX;
837 }
838
839 static u16
840 biosfn_restore_video_state(u16 CX, u16 ES, u16 BX)
841 {
842     if (CX & 1) {
843         // Reset Attribute Ctl flip-flop
844         inb(VGAREG_ACTL_RESET);
845
846         u16 crtc_addr = GET_FARVAR(ES, *(u16*)(BX + 0x40));
847         u16 addr1 = BX;
848         BX += 5;
849
850         u16 i;
851         for (i = 1; i <= 4; i++) {
852             outb(i, VGAREG_SEQU_ADDRESS);
853             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_SEQU_DATA);
854             BX++;
855         }
856         outb(0, VGAREG_SEQU_ADDRESS);
857         outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_SEQU_DATA);
858         BX++;
859
860         // Disable CRTC write protection
861         outw(0x0011, crtc_addr);
862         // Set CRTC regs
863         for (i = 0; i <= 0x18; i++) {
864             if (i != 0x11) {
865                 outb(i, crtc_addr);
866                 outb(GET_FARVAR(ES, *(u8*)(BX+0)), crtc_addr + 1);
867             }
868             BX++;
869         }
870         // select crtc base address
871         u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
872         if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
873             v |= 0x01;
874         outb(v, VGAREG_WRITE_MISC_OUTPUT);
875
876         // enable write protection if needed
877         outb(0x11, crtc_addr);
878         outb(GET_FARVAR(ES, *(u8*)(BX - 0x18 + 0x11)), crtc_addr + 1);
879
880         // Set Attribute Ctl
881         u16 ar_index = GET_FARVAR(ES, *(u8*)(addr1 + 0x03));
882         inb(VGAREG_ACTL_RESET);
883         for (i = 0; i <= 0x13; i++) {
884             outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
885             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_ACTL_WRITE_DATA);
886             BX++;
887         }
888         outb(ar_index, VGAREG_ACTL_ADDRESS);
889         inb(VGAREG_ACTL_RESET);
890
891         for (i = 0; i <= 8; i++) {
892             outb(i, VGAREG_GRDC_ADDRESS);
893             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_GRDC_DATA);
894             BX++;
895         }
896         BX += 2;                /* crtc_addr */
897         BX += 4;                /* plane latches */
898
899         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), VGAREG_SEQU_ADDRESS);
900         addr1++;
901         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), crtc_addr);
902         addr1++;
903         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), VGAREG_GRDC_ADDRESS);
904         addr1++;
905         addr1++;
906         outb(GET_FARVAR(ES, *(u8*)(addr1+0)), crtc_addr - 0x4 + 0xa);
907         addr1++;
908     }
909     if (CX & 2) {
910         SET_BDA(video_mode, GET_FARVAR(ES, *(u8*)(BX+0)));
911         BX++;
912         SET_BDA(video_cols, GET_FARVAR(ES, *(u16*)(BX+0)));
913         BX += 2;
914         SET_BDA(video_pagesize, GET_FARVAR(ES, *(u16*)(BX+0)));
915         BX += 2;
916         SET_BDA(crtc_address, GET_FARVAR(ES, *(u16*)(BX+0)));
917         BX += 2;
918         SET_BDA(video_rows, GET_FARVAR(ES, *(u8*)(BX+0)));
919         BX++;
920         SET_BDA(char_height, GET_FARVAR(ES, *(u16*)(BX+0)));
921         BX += 2;
922         SET_BDA(video_ctl, GET_FARVAR(ES, *(u8*)(BX+0)));
923         BX++;
924         SET_BDA(video_switches, GET_FARVAR(ES, *(u8*)(BX+0)));
925         BX++;
926         SET_BDA(modeset_ctl, GET_FARVAR(ES, *(u8*)(BX+0)));
927         BX++;
928         SET_BDA(cursor_type, GET_FARVAR(ES, *(u16*)(BX+0)));
929         BX += 2;
930         u16 i;
931         for (i = 0; i < 8; i++) {
932             SET_BDA(cursor_pos[i], GET_FARVAR(ES, *(u16*)(BX+0)));
933             BX += 2;
934         }
935         SET_BDA(video_pagestart, GET_FARVAR(ES, *(u16*)(BX+0)));
936         BX += 2;
937         SET_BDA(video_page, GET_FARVAR(ES, *(u8*)(BX+0)));
938         BX++;
939         /* current font */
940         SET_IVT(0x1f, GET_FARVAR(ES, *(u16*)(BX+2)), GET_FARVAR(ES, *(u16*)(BX+0)));
941         BX += 4;
942         SET_IVT(0x43, GET_FARVAR(ES, *(u16*)(BX+2)), GET_FARVAR(ES, *(u16*)(BX+0)));
943         BX += 4;
944     }
945     if (CX & 4) {
946         BX++;
947         u16 v = GET_FARVAR(ES, *(u8*)(BX+0));
948         BX++;
949         outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_PEL_MASK);
950         BX++;
951         // Set the whole dac always, from 0
952         outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
953         u16 i;
954         for (i = 0; i < 256 * 3; i++) {
955             outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_DAC_DATA);
956             BX++;
957         }
958         BX++;
959         outb(v, VGAREG_DAC_WRITE_ADDRESS);
960     }
961     return BX;
962 }
963
964
965 /****************************************************************
966  * VGA int 10 handler
967  ****************************************************************/
968
969 static void
970 handle_1000(struct bregs *regs)
971 {
972     // XXX - inline
973     biosfn_set_video_mode(regs->al);
974     switch(regs->al & 0x7F) {
975     case 6:
976         regs->al = 0x3F;
977         break;
978     case 0:
979     case 1:
980     case 2:
981     case 3:
982     case 4:
983     case 5:
984     case 7:
985         regs->al = 0x30;
986         break;
987     default:
988         regs->al = 0x20;
989     }
990 }
991
992 static void
993 handle_1001(struct bregs *regs)
994 {
995     biosfn_set_cursor_shape(regs->ch, regs->cl);
996 }
997
998 static void
999 handle_1002(struct bregs *regs)
1000 {
1001     biosfn_set_cursor_pos(regs->bh, regs->dx);
1002 }
1003
1004 static void
1005 handle_1003(struct bregs *regs)
1006 {
1007     regs->cx = biosfn_get_cursor_shape(regs->bh);
1008     regs->dx = biosfn_get_cursor_pos(regs->bh);
1009 }
1010
1011 // Read light pen pos (unimplemented)
1012 static void
1013 handle_1004(struct bregs *regs)
1014 {
1015     debug_stub(regs);
1016     regs->ax = regs->bx = regs->cx = regs->dx = 0;
1017 }
1018
1019 static void
1020 handle_1005(struct bregs *regs)
1021 {
1022     biosfn_set_active_page(regs->al);
1023 }
1024
1025 static void
1026 handle_1006(struct bregs *regs)
1027 {
1028     biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
1029                   , 0xFF, SCROLL_UP);
1030 }
1031
1032 static void
1033 handle_1007(struct bregs *regs)
1034 {
1035     biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
1036                   , 0xFF, SCROLL_DOWN);
1037 }
1038
1039 static void
1040 handle_1008(struct bregs *regs)
1041 {
1042     // XXX - inline
1043     biosfn_read_char_attr(regs->bh, &regs->ax);
1044 }
1045
1046 static void
1047 handle_1009(struct bregs *regs)
1048 {
1049     // XXX - inline
1050     biosfn_write_char_attr(regs->al, regs->bh, regs->bl, regs->cx);
1051 }
1052
1053 static void
1054 handle_100a(struct bregs *regs)
1055 {
1056     // XXX - inline
1057     biosfn_write_char_only(regs->al, regs->bh, regs->bl, regs->cx);
1058 }
1059
1060
1061 static void
1062 handle_100b00(struct bregs *regs)
1063 {
1064     // XXX - inline
1065     biosfn_set_border_color(regs);
1066 }
1067
1068 static void
1069 handle_100b01(struct bregs *regs)
1070 {
1071     // XXX - inline
1072     biosfn_set_palette(regs);
1073 }
1074
1075 static void
1076 handle_100bXX(struct bregs *regs)
1077 {
1078     debug_stub(regs);
1079 }
1080
1081 static void
1082 handle_100b(struct bregs *regs)
1083 {
1084     switch (regs->bh) {
1085     case 0x00: handle_100b00(regs); break;
1086     case 0x01: handle_100b01(regs); break;
1087     default:   handle_100bXX(regs); break;
1088     }
1089 }
1090
1091
1092 static void
1093 handle_100c(struct bregs *regs)
1094 {
1095     // XXX - inline
1096     biosfn_write_pixel(regs->bh, regs->al, regs->cx, regs->dx);
1097 }
1098
1099 static void
1100 handle_100d(struct bregs *regs)
1101 {
1102     // XXX - inline
1103     biosfn_read_pixel(regs->bh, regs->cx, regs->dx, &regs->ax);
1104 }
1105
1106 static void
1107 handle_100e(struct bregs *regs)
1108 {
1109     // Ralf Brown Interrupt list is WRONG on bh(page)
1110     // We do output only on the current page !
1111     biosfn_write_teletype(regs->al, 0xff, regs->bl, NO_ATTR);
1112 }
1113
1114 static void
1115 handle_100f(struct bregs *regs)
1116 {
1117     // XXX - inline
1118     biosfn_get_video_mode(regs);
1119 }
1120
1121
1122 static void
1123 handle_101000(struct bregs *regs)
1124 {
1125     if (regs->bl > 0x14)
1126         return;
1127     biosfn_set_single_palette_reg(regs->bl, regs->bh);
1128 }
1129
1130 static void
1131 handle_101001(struct bregs *regs)
1132 {
1133     // XXX - inline
1134     biosfn_set_overscan_border_color(regs);
1135 }
1136
1137 static void
1138 handle_101002(struct bregs *regs)
1139 {
1140     // XXX - inline
1141     biosfn_set_all_palette_reg(regs);
1142 }
1143
1144 static void
1145 handle_101003(struct bregs *regs)
1146 {
1147     // XXX - inline
1148     biosfn_toggle_intensity(regs);
1149 }
1150
1151 static void
1152 handle_101007(struct bregs *regs)
1153 {
1154     if (regs->bl > 0x14)
1155         return;
1156     regs->bh = biosfn_get_single_palette_reg(regs->bl);
1157 }
1158
1159 static void
1160 handle_101008(struct bregs *regs)
1161 {
1162     // XXX - inline
1163     biosfn_read_overscan_border_color(regs);
1164 }
1165
1166 static void
1167 handle_101009(struct bregs *regs)
1168 {
1169     // XXX - inline
1170     biosfn_get_all_palette_reg(regs);
1171 }
1172
1173 static void
1174 handle_101010(struct bregs *regs)
1175 {
1176     // XXX - inline
1177     biosfn_set_single_dac_reg(regs);
1178 }
1179
1180 static void
1181 handle_101012(struct bregs *regs)
1182 {
1183     // XXX - inline
1184     biosfn_set_all_dac_reg(regs);
1185 }
1186
1187 static void
1188 handle_101013(struct bregs *regs)
1189 {
1190     // XXX - inline
1191     biosfn_select_video_dac_color_page(regs);
1192 }
1193
1194 static void
1195 handle_101015(struct bregs *regs)
1196 {
1197     // XXX - inline
1198     biosfn_read_single_dac_reg(regs);
1199 }
1200
1201 static void
1202 handle_101017(struct bregs *regs)
1203 {
1204     // XXX - inline
1205     biosfn_read_all_dac_reg(regs);
1206 }
1207
1208 static void
1209 handle_101018(struct bregs *regs)
1210 {
1211     // XXX - inline
1212     biosfn_set_pel_mask(regs);
1213 }
1214
1215 static void
1216 handle_101019(struct bregs *regs)
1217 {
1218     // XXX - inline
1219     biosfn_read_pel_mask(regs);
1220 }
1221
1222 static void
1223 handle_10101a(struct bregs *regs)
1224 {
1225     // XXX - inline
1226     biosfn_read_video_dac_state(regs);
1227 }
1228
1229 static void
1230 handle_10101b(struct bregs *regs)
1231 {
1232     biosfn_perform_gray_scale_summing(regs->bx, regs->cx);
1233 }
1234
1235 static void
1236 handle_1010XX(struct bregs *regs)
1237 {
1238     debug_stub(regs);
1239 }
1240
1241 static void
1242 handle_1010(struct bregs *regs)
1243 {
1244     switch (regs->al) {
1245     case 0x00: handle_101000(regs); break;
1246     case 0x01: handle_101001(regs); break;
1247     case 0x02: handle_101002(regs); break;
1248     case 0x03: handle_101003(regs); break;
1249     case 0x07: handle_101007(regs); break;
1250     case 0x08: handle_101008(regs); break;
1251     case 0x09: handle_101009(regs); break;
1252     case 0x10: handle_101010(regs); break;
1253     case 0x12: handle_101012(regs); break;
1254     case 0x13: handle_101013(regs); break;
1255     case 0x15: handle_101015(regs); break;
1256     case 0x17: handle_101017(regs); break;
1257     case 0x18: handle_101018(regs); break;
1258     case 0x19: handle_101019(regs); break;
1259     case 0x1a: handle_10101a(regs); break;
1260     case 0x1b: handle_10101b(regs); break;
1261     default:   handle_1010XX(regs); break;
1262     }
1263 }
1264
1265
1266 static void
1267 handle_101100(struct bregs *regs)
1268 {
1269     biosfn_load_text_user_pat(regs->es, regs->bp
1270                               , regs->cx, regs->dx, regs->bl, regs->bh);
1271 }
1272
1273 static void
1274 handle_101101(struct bregs *regs)
1275 {
1276     biosfn_load_text_8_14_pat(regs->bl);
1277 }
1278
1279 static void
1280 handle_101102(struct bregs *regs)
1281 {
1282     biosfn_load_text_8_8_pat(regs->bl);
1283 }
1284
1285 static void
1286 handle_101103(struct bregs *regs)
1287 {
1288     // XXX - inline
1289     biosfn_set_text_block_specifier(regs);
1290 }
1291
1292 static void
1293 handle_101104(struct bregs *regs)
1294 {
1295     biosfn_load_text_8_16_pat(regs->bl);
1296 }
1297
1298 static void
1299 handle_101110(struct bregs *regs)
1300 {
1301     biosfn_load_text_user_pat(regs->es, regs->bp
1302                               , regs->cx, regs->dx, regs->bl, regs->bh);
1303     set_scan_lines(regs->bh);
1304 }
1305
1306 static void
1307 handle_101111(struct bregs *regs)
1308 {
1309     biosfn_load_text_8_14_pat(regs->bl);
1310     set_scan_lines(14);
1311 }
1312
1313 static void
1314 handle_101112(struct bregs *regs)
1315 {
1316     biosfn_load_text_8_8_pat(regs->bl);
1317     set_scan_lines(8);
1318 }
1319
1320 static void
1321 handle_101114(struct bregs *regs)
1322 {
1323     biosfn_load_text_8_16_pat(regs->bl);
1324     set_scan_lines(16);
1325 }
1326
1327 static void
1328 handle_101130(struct bregs *regs)
1329 {
1330     // XXX - inline
1331     biosfn_get_font_info(regs->bh, &regs->es, &regs->bp
1332                          , &regs->cx, &regs->dx);
1333 }
1334
1335 static void
1336 handle_1011XX(struct bregs *regs)
1337 {
1338     debug_stub(regs);
1339 }
1340
1341 static void
1342 handle_1011(struct bregs *regs)
1343 {
1344     switch (regs->al) {
1345     case 0x00: handle_101100(regs); break;
1346     case 0x01: handle_101101(regs); break;
1347     case 0x02: handle_101102(regs); break;
1348     case 0x03: handle_101103(regs); break;
1349     case 0x04: handle_101104(regs); break;
1350     case 0x10: handle_101110(regs); break;
1351     case 0x11: handle_101111(regs); break;
1352     case 0x12: handle_101112(regs); break;
1353     case 0x14: handle_101114(regs); break;
1354     case 0x30: handle_101130(regs); break;
1355     default:   handle_1011XX(regs); break;
1356     }
1357 }
1358
1359
1360 static void
1361 handle_101210(struct bregs *regs)
1362 {
1363     // XXX - inline
1364     biosfn_get_ega_info(regs);
1365 }
1366
1367 static void
1368 handle_101230(struct bregs *regs)
1369 {
1370     // XXX - inline
1371     biosfn_select_vert_res(regs);
1372 }
1373
1374 static void
1375 handle_101231(struct bregs *regs)
1376 {
1377     // XXX - inline
1378     biosfn_enable_default_palette_loading(regs);
1379 }
1380
1381 static void
1382 handle_101232(struct bregs *regs)
1383 {
1384     // XXX - inline
1385     biosfn_enable_video_addressing(regs);
1386 }
1387
1388 static void
1389 handle_101233(struct bregs *regs)
1390 {
1391     // XXX - inline
1392     biosfn_enable_grayscale_summing(regs);
1393 }
1394
1395 static void
1396 handle_101234(struct bregs *regs)
1397 {
1398     // XXX - inline
1399     biosfn_enable_cursor_emulation(regs);
1400 }
1401
1402 static void
1403 handle_101235(struct bregs *regs)
1404 {
1405     debug_stub(regs);
1406     regs->al = 0x12;
1407 }
1408
1409 static void
1410 handle_101236(struct bregs *regs)
1411 {
1412     debug_stub(regs);
1413     regs->al = 0x12;
1414 }
1415
1416 static void
1417 handle_1012XX(struct bregs *regs)
1418 {
1419     debug_stub(regs);
1420 }
1421
1422 static void
1423 handle_1012(struct bregs *regs)
1424 {
1425     switch (regs->bl) {
1426     case 0x10: handle_101210(regs); break;
1427     case 0x30: handle_101230(regs); break;
1428     case 0x31: handle_101231(regs); break;
1429     case 0x32: handle_101232(regs); break;
1430     case 0x33: handle_101233(regs); break;
1431     case 0x34: handle_101234(regs); break;
1432     case 0x35: handle_101235(regs); break;
1433     case 0x36: handle_101236(regs); break;
1434     default:   handle_1012XX(regs); break;
1435     }
1436
1437     // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
1438 }
1439
1440
1441 static void
1442 handle_1013(struct bregs *regs)
1443 {
1444     // XXX - inline
1445     biosfn_write_string(regs->al, regs->bh, regs->bl, regs->cx
1446                         , regs->dh, regs->dl, regs->es, (void*)(regs->bp + 0));
1447 }
1448
1449
1450 static void
1451 handle_101a00(struct bregs *regs)
1452 {
1453     // XXX - inline
1454     biosfn_read_display_code(regs);
1455 }
1456
1457 static void
1458 handle_101a01(struct bregs *regs)
1459 {
1460     // XXX - inline
1461     biosfn_set_display_code(regs);
1462 }
1463
1464 static void
1465 handle_101aXX(struct bregs *regs)
1466 {
1467     debug_stub(regs);
1468 }
1469
1470 static void
1471 handle_101a(struct bregs *regs)
1472 {
1473     switch (regs->al) {
1474     case 0x00: handle_101a00(regs); break;
1475     case 0x01: handle_101a01(regs); break;
1476     default:   handle_101aXX(regs); break;
1477     }
1478 }
1479
1480
1481 static void
1482 handle_101b(struct bregs *regs)
1483 {
1484     // XXX - inline
1485     biosfn_read_state_info(regs->bx, regs->es, regs->di);
1486     regs->al = 0x1B;
1487 }
1488
1489
1490 static void
1491 handle_101c00(struct bregs *regs)
1492 {
1493     // XXX - inline
1494     regs->bx = biosfn_read_video_state_size(regs->cx);
1495 }
1496
1497 static void
1498 handle_101c01(struct bregs *regs)
1499 {
1500     // XXX - inline
1501     biosfn_save_video_state(regs->cx, regs->es, regs->bx);
1502 }
1503
1504 static void
1505 handle_101c02(struct bregs *regs)
1506 {
1507     // XXX - inline
1508     biosfn_restore_video_state(regs->cx, regs->es, regs->bx);
1509 }
1510
1511 static void
1512 handle_101cXX(struct bregs *regs)
1513 {
1514     debug_stub(regs);
1515 }
1516
1517 static void
1518 handle_101c(struct bregs *regs)
1519 {
1520     switch (regs->al) {
1521     case 0x00: handle_101c00(regs); break;
1522     case 0x01: handle_101c01(regs); break;
1523     case 0x02: handle_101c02(regs); break;
1524     default:   handle_101cXX(regs); break;
1525     }
1526 }
1527
1528
1529 static void
1530 handle_104f00(struct bregs *regs)
1531 {
1532     // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
1533     // XXX - OR cirrus_vesa_00h
1534 }
1535
1536 static void
1537 handle_104f01(struct bregs *regs)
1538 {
1539     // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
1540     // XXX - OR cirrus_vesa_01h
1541 }
1542
1543 static void
1544 handle_104f02(struct bregs *regs)
1545 {
1546     // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
1547     // XXX - OR cirrus_vesa_02h
1548 }
1549
1550 static void
1551 handle_104f03(struct bregs *regs)
1552 {
1553     // XXX - vbe_biosfn_return_current_mode
1554     // XXX - OR cirrus_vesa_03h
1555 }
1556
1557 static void
1558 handle_104f04(struct bregs *regs)
1559 {
1560     // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
1561 }
1562
1563 static void
1564 handle_104f05(struct bregs *regs)
1565 {
1566     // XXX - vbe_biosfn_display_window_control
1567     // XXX - OR cirrus_vesa_05h
1568 }
1569
1570 static void
1571 handle_104f06(struct bregs *regs)
1572 {
1573     // XXX - vbe_biosfn_set_get_logical_scan_line_length
1574     // XXX - OR cirrus_vesa_06h
1575 }
1576
1577 static void
1578 handle_104f07(struct bregs *regs)
1579 {
1580     // XXX - vbe_biosfn_set_get_display_start
1581     // XXX - OR cirrus_vesa_07h
1582 }
1583
1584 static void
1585 handle_104f08(struct bregs *regs)
1586 {
1587     // XXX - vbe_biosfn_set_get_dac_palette_format
1588 }
1589
1590 static void
1591 handle_104f0a(struct bregs *regs)
1592 {
1593     // XXX - vbe_biosfn_return_protected_mode_interface
1594 }
1595
1596 static void
1597 handle_104fXX(struct bregs *regs)
1598 {
1599     debug_stub(regs);
1600     regs->ax = 0x0100;
1601 }
1602
1603 static void
1604 handle_104f(struct bregs *regs)
1605 {
1606     if (! CONFIG_VBE || !vbe_has_vbe_display()) {
1607         handle_104fXX(regs);
1608         return;
1609     }
1610
1611     switch (regs->al) {
1612     case 0x00: handle_104f00(regs); break;
1613     case 0x01: handle_104f01(regs); break;
1614     case 0x02: handle_104f02(regs); break;
1615     case 0x03: handle_104f03(regs); break;
1616     case 0x04: handle_104f04(regs); break;
1617     case 0x05: handle_104f05(regs); break;
1618     case 0x06: handle_104f06(regs); break;
1619     case 0x07: handle_104f07(regs); break;
1620     case 0x08: handle_104f08(regs); break;
1621     case 0x0a: handle_104f0a(regs); break;
1622     default:   handle_104fXX(regs); break;
1623     }
1624 }
1625
1626
1627 static void
1628 handle_10XX(struct bregs *regs)
1629 {
1630     debug_stub(regs);
1631 }
1632
1633 // INT 10h Video Support Service Entry Point
1634 void VISIBLE16
1635 handle_10(struct bregs *regs)
1636 {
1637     debug_enter(regs, DEBUG_VGA_10);
1638     switch (regs->ah) {
1639     case 0x00: handle_1000(regs); break;
1640     case 0x01: handle_1001(regs); break;
1641     case 0x02: handle_1002(regs); break;
1642     case 0x03: handle_1003(regs); break;
1643     case 0x04: handle_1004(regs); break;
1644     case 0x05: handle_1005(regs); break;
1645     case 0x06: handle_1006(regs); break;
1646     case 0x07: handle_1007(regs); break;
1647     case 0x08: handle_1008(regs); break;
1648     case 0x09: handle_1009(regs); break;
1649     case 0x0a: handle_100a(regs); break;
1650     case 0x0b: handle_100b(regs); break;
1651     case 0x0c: handle_100c(regs); break;
1652     case 0x0d: handle_100d(regs); break;
1653     case 0x0e: handle_100e(regs); break;
1654     case 0x0f: handle_100f(regs); break;
1655     case 0x10: handle_1010(regs); break;
1656     case 0x11: handle_1011(regs); break;
1657     case 0x12: handle_1012(regs); break;
1658     case 0x13: handle_1013(regs); break;
1659     case 0x1a: handle_101a(regs); break;
1660     case 0x1b: handle_101b(regs); break;
1661     case 0x1c: handle_101c(regs); break;
1662     case 0x4f: handle_104f(regs); break;
1663     default:   handle_10XX(regs); break;
1664     }
1665 }
1666
1667
1668 /****************************************************************
1669  * VGA post
1670  ****************************************************************/
1671
1672 static void
1673 init_bios_area()
1674 {
1675     // init detected hardware BIOS Area
1676     // set 80x25 color (not clear from RBIL but usual)
1677     u16 eqf = GET_BDA(equipment_list_flags);
1678     SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1679
1680     // Just for the first int10 find its children
1681
1682     // the default char height
1683     SET_BDA(char_height, 0x10);
1684
1685     // Clear the screen
1686     SET_BDA(video_ctl, 0x60);
1687
1688     // Set the basic screen we have
1689     SET_BDA(video_switches, 0xf9);
1690
1691     // Set the basic modeset options
1692     SET_BDA(modeset_ctl, 0x51);
1693
1694     // Set the  default MSR
1695     SET_BDA(video_msr, 0x09);
1696 }
1697
1698 void VISIBLE16
1699 vga_post(struct bregs *regs)
1700 {
1701     debug_enter(regs, DEBUG_VGA_POST);
1702
1703     init_vga_card();
1704
1705     init_bios_area();
1706
1707     if (CONFIG_VBE)
1708         vbe_init();
1709
1710     extern void entry_10(void);
1711     SET_IVT(0x10, get_global_seg(), (u32)entry_10);
1712
1713     if (CONFIG_CIRRUS)
1714         cirrus_init();
1715
1716     // XXX - clear screen and display info
1717
1718     // XXX: fill it
1719     SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
1720     SET_VGA(video_save_pointer_table[1], get_global_seg());
1721
1722     // Fixup checksum
1723     extern u8 _rom_header_size, _rom_header_checksum;
1724     SET_VGA(_rom_header_checksum, 0);
1725     u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
1726     SET_VGA(_rom_header_checksum, sum);
1727 }