VGA: Replace biosfn_load_text_* with vgafb_load_font().
[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 //  * remove recursion from biosfn_write_teletype()
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 #include "bregs.h" // struct bregs
20 #include "biosvar.h" // GET_BDA
21 #include "util.h" // memset
22 #include "vgatables.h" // find_vga_entry
23
24 // XXX
25 #define CONFIG_VBE 0
26 #define CONFIG_CIRRUS 0
27
28 // XXX
29 #define DEBUG_VGA_POST 1
30 #define DEBUG_VGA_10 3
31
32 #define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
33
34
35 // ===================================================================
36 //
37 // Video Utils
38 //
39 // ===================================================================
40
41 // -------------------------------------------------------------------
42 inline void
43 call16_vgaint(u32 eax, u32 ebx)
44 {
45     asm volatile(
46         "int $0x10\n"
47         "cli\n"
48         "cld"
49         :
50         : "a"(eax), "b"(ebx)
51         : "cc", "memory");
52 }
53
54
55 // ===================================================================
56 //
57 // BIOS functions
58 //
59 // ===================================================================
60
61 // -------------------------------------------------------------------
62 static void
63 biosfn_perform_gray_scale_summing(u16 start, u16 count)
64 {
65     vgahw_screen_disable();
66     int i;
67     for (i = start; i < start+count; i++) {
68         u8 rgb[3];
69         vgahw_get_dac_regs(GET_SEG(SS), rgb, i, 1);
70
71         // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
72         u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
73         if (intensity > 0x3f)
74             intensity = 0x3f;
75
76         vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1);
77     }
78     vgahw_screen_enable();
79 }
80
81 // -------------------------------------------------------------------
82 static void
83 biosfn_set_cursor_shape(u8 CH, u8 CL)
84 {
85     CH &= 0x3f;
86     CL &= 0x1f;
87
88     u16 curs = (CH << 8) + CL;
89     SET_BDA(cursor_type, curs);
90
91     u8 modeset_ctl = GET_BDA(modeset_ctl);
92     u16 cheight = GET_BDA(char_height);
93     if ((modeset_ctl & 0x01) && (cheight > 8) && (CL < 8) && (CH < 0x20)) {
94         if (CL != (CH + 1))
95             CH = ((CH + 1) * cheight / 8) - 1;
96         else
97             CH = ((CL + 1) * cheight / 8) - 2;
98         CL = ((CL + 1) * cheight / 8) - 1;
99     }
100     vgahw_set_cursor_shape(CH, CL);
101 }
102
103 static u16
104 biosfn_get_cursor_shape(u8 page)
105 {
106     if (page > 7)
107         return 0;
108     // FIXME should handle VGA 14/16 lines
109     return GET_BDA(cursor_type);
110 }
111
112 // -------------------------------------------------------------------
113 static void
114 biosfn_set_cursor_pos(u8 page, u16 cursor)
115 {
116     // Should not happen...
117     if (page > 7)
118         return;
119
120     // Bios cursor pos
121     SET_BDA(cursor_pos[page], cursor);
122
123     // Set the hardware cursor
124     u8 current = GET_BDA(video_page);
125     if (page != current)
126         return;
127
128     // Get the dimensions
129     u16 nbcols = GET_BDA(video_cols);
130     u16 nbrows = GET_BDA(video_rows) + 1;
131
132     u8 xcurs = cursor & 0x00ff;
133     u8 ycurs = (cursor & 0xff00) >> 8;
134
135     // Calculate the address knowing nbcols nbrows and page num
136     u16 address = SCREEN_IO_START(nbcols, nbrows, page) + xcurs + ycurs * nbcols;
137
138     vgahw_set_cursor_pos(address);
139 }
140
141 u16
142 biosfn_get_cursor_pos(u8 page)
143 {
144     if (page > 7)
145         return 0;
146     // FIXME should handle VGA 14/16 lines
147     return GET_BDA(cursor_pos[page]);
148 }
149
150 // -------------------------------------------------------------------
151 static void
152 biosfn_set_active_page(u8 page)
153 {
154     if (page > 7)
155         return;
156
157     // Get the mode
158     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
159     if (!vmode_g)
160         return;
161
162     // Get pos curs pos for the right page
163     u16 cursor = biosfn_get_cursor_pos(page);
164
165     u16 address;
166     if (GET_GLOBAL(vmode_g->class) == TEXT) {
167         // Get the dimensions
168         u16 nbcols = GET_BDA(video_cols);
169         u16 nbrows = GET_BDA(video_rows) + 1;
170
171         // Calculate the address knowing nbcols nbrows and page num
172         address = SCREEN_MEM_START(nbcols, nbrows, page);
173         SET_BDA(video_pagestart, address);
174
175         // Start address
176         address = SCREEN_IO_START(nbcols, nbrows, page);
177     } else {
178         struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
179         address = page * GET_GLOBAL(vparam_g->slength);
180     }
181
182     vgahw_set_active_page(address);
183
184     // And change the BIOS page
185     SET_BDA(video_page, page);
186
187     dprintf(1, "Set active page %02x address %04x\n", page, address);
188
189     // Display the cursor, now the page is active
190     biosfn_set_cursor_pos(page, cursor);
191 }
192
193 static void
194 biosfn_set_video_mode(u8 mode)
195 {                               // mode: Bit 7 is 1 if no clear screen
196     if (CONFIG_CIRRUS)
197         cirrus_set_video_mode(mode);
198
199     if (CONFIG_VBE)
200         if (vbe_has_vbe_display())
201             dispi_set_enable(VBE_DISPI_DISABLED);
202
203     // The real mode
204     u8 noclearmem = mode & 0x80;
205     mode = mode & 0x7f;
206
207     // find the entry in the video modes
208     struct vgamode_s *vmode_g = find_vga_entry(mode);
209     dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
210     if (!vmode_g)
211         return;
212
213     // Read the bios mode set control
214     u8 modeset_ctl = GET_BDA(modeset_ctl);
215
216     // Then we know the number of lines
217 // FIXME
218
219     // if palette loading (bit 3 of modeset ctl = 0)
220     if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
221         vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
222
223         // From which palette
224         u8 *palette_g = GET_GLOBAL(vmode_g->dac);
225         u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
226
227         // Always 256*3 values
228         vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
229         u16 i;
230         for (i = palsize; i < 0x0100; i++) {
231             static u8 rgb[3] VAR16;
232             vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
233         }
234
235         if ((modeset_ctl & 0x02) == 0x02)
236             biosfn_perform_gray_scale_summing(0x00, 0x100);
237     }
238
239     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
240     vgahw_set_mode(vparam_g);
241
242     if (noclearmem == 0x00)
243         clear_screen(vmode_g);
244
245     // Set CRTC address VGA or MDA
246     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
247     if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
248         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
249
250     // Set the BIOS mem
251     u16 cheight = GET_GLOBAL(vparam_g->cheight);
252     SET_BDA(video_mode, mode);
253     SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
254     SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
255     SET_BDA(crtc_address, crtc_addr);
256     SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
257     SET_BDA(char_height, cheight);
258     SET_BDA(video_ctl, (0x60 | noclearmem));
259     SET_BDA(video_switches, 0xF9);
260     SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
261
262     // FIXME We nearly have the good tables. to be reworked
263     SET_BDA(dcc_index, 0x08);   // 8 is VGA should be ok for now
264     SET_BDA(video_savetable_ptr, (u32)video_save_pointer_table);
265     SET_BDA(video_savetable_seg, get_global_seg());
266
267     // FIXME
268     SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
269     SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
270
271     // Set cursor shape
272     if (GET_GLOBAL(vmode_g->class) == TEXT)
273         biosfn_set_cursor_shape(0x06, 0x07);
274     // Set cursor pos for page 0..7
275     int i;
276     for (i = 0; i < 8; i++)
277         biosfn_set_cursor_pos(i, 0x0000);
278
279     // Set active page 0
280     biosfn_set_active_page(0x00);
281
282     // Write the fonts in memory
283     if (GET_GLOBAL(vmode_g->class) == TEXT) {
284         call16_vgaint(0x1104, 0);
285         call16_vgaint(0x1103, 0);
286     }
287     // Set the ints 0x1F and 0x43
288     SET_IVT(0x1f, get_global_seg(), (u32)&vgafont8[128 * 8]);
289
290     switch (cheight) {
291     case 8:
292         SET_IVT(0x43, get_global_seg(), (u32)vgafont8);
293         break;
294     case 14:
295         SET_IVT(0x43, get_global_seg(), (u32)vgafont14);
296         break;
297     case 16:
298         SET_IVT(0x43, get_global_seg(), (u32)vgafont16);
299         break;
300     }
301 }
302
303 // -------------------------------------------------------------------
304 static void
305 biosfn_write_teletype(u8 car, u8 page, u8 attr, u8 flag)
306 {                               // flag = WITH_ATTR / NO_ATTR
307     // special case if page is 0xff, use current page
308     if (page == 0xff)
309         page = GET_BDA(video_page);
310
311     // Get the mode
312     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
313     if (!vmode_g)
314         return;
315
316     // Get the cursor pos for the page
317     u16 cursor = biosfn_get_cursor_pos(page);
318     u8 xcurs = cursor & 0x00ff;
319     u8 ycurs = (cursor & 0xff00) >> 8;
320
321     // Get the dimensions
322     u16 nbrows = GET_BDA(video_rows) + 1;
323     u16 nbcols = GET_BDA(video_cols);
324
325     switch (car) {
326     case 7:
327         //FIXME should beep
328         break;
329
330     case 8:
331         if (xcurs > 0)
332             xcurs--;
333         break;
334
335     case '\r':
336         xcurs = 0;
337         break;
338
339     case '\n':
340         ycurs++;
341         break;
342
343     case '\t':
344         do {
345             biosfn_write_teletype(' ', page, attr, flag);
346             cursor = biosfn_get_cursor_pos(page);
347             xcurs = cursor & 0x00ff;
348             ycurs = (cursor & 0xff00) >> 8;
349         } while (xcurs % 8 == 0);
350         break;
351
352     default:
353         if (flag == WITH_ATTR)
354             biosfn_write_char_attr(car, page, attr, 1);
355         else
356             biosfn_write_char_only(car, page, attr, 1);
357         xcurs++;
358     }
359
360     // Do we need to wrap ?
361     if (xcurs == nbcols) {
362         xcurs = 0;
363         ycurs++;
364     }
365     // Do we need to scroll ?
366     if (ycurs == nbrows) {
367         if (GET_GLOBAL(vmode_g->class) == TEXT)
368             biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, page,
369                           SCROLL_UP);
370         else
371             biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, page,
372                           SCROLL_UP);
373         ycurs -= 1;
374     }
375     // Set the cursor for the page
376     cursor = ycurs;
377     cursor <<= 8;
378     cursor += xcurs;
379     biosfn_set_cursor_pos(page, cursor);
380 }
381
382 static void
383 biosfn_write_string(u8 flag, u8 page, u8 attr, u16 count, u8 row, u8 col,
384                     u16 seg, u8 *offset_far)
385 {
386     // Read curs info for the page
387     u16 oldcurs = biosfn_get_cursor_pos(page);
388
389     // if row=0xff special case : use current cursor position
390     if (row == 0xff) {
391         col = oldcurs & 0x00ff;
392         row = (oldcurs & 0xff00) >> 8;
393     }
394
395     u16 newcurs = row;
396     newcurs <<= 8;
397     newcurs += col;
398     biosfn_set_cursor_pos(page, newcurs);
399
400     while (count-- != 0) {
401         u8 car = GET_FARVAR(seg, *offset_far);
402         offset_far++;
403         if ((flag & 0x02) != 0) {
404             attr = GET_FARVAR(seg, *offset_far);
405             offset_far++;
406         }
407
408         biosfn_write_teletype(car, page, attr, WITH_ATTR);
409     }
410
411     // Set back curs pos
412     if ((flag & 0x01) == 0)
413         biosfn_set_cursor_pos(page, oldcurs);
414 }
415
416 static void
417 set_scan_lines(u8 lines)
418 {
419     vgahw_set_scan_lines(lines);
420     if (lines == 8)
421         biosfn_set_cursor_shape(0x06, 0x07);
422     else
423         biosfn_set_cursor_shape(lines - 4, lines - 3);
424     SET_BDA(char_height, lines);
425     u16 vde = vgahw_get_vde();
426     u8 rows = vde / lines;
427     SET_BDA(video_rows, rows - 1);
428     u16 cols = GET_BDA(video_cols);
429     SET_BDA(video_pagesize, rows * cols * 2);
430 }
431
432 static void
433 biosfn_save_bda_state(u16 seg, struct saveBDAstate *info)
434 {
435     SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
436     SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
437     SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
438     SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
439     SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
440     SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
441     SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
442     SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
443     SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
444     SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
445     u16 i;
446     for (i=0; i<8; i++)
447         SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
448     SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
449     SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
450     /* current font */
451     SET_FARVAR(seg, *(u32*)&info->font0_off, GET_IVT(0x1f).segoff);
452     SET_FARVAR(seg, *(u32*)&info->font1_off, GET_IVT(0x43).segoff);
453 }
454
455 static void
456 biosfn_restore_bda_state(u16 seg, struct saveBDAstate *info)
457 {
458     SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
459     SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
460     SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
461     SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
462     SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
463     SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
464     SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
465     SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
466     SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
467     SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
468     u16 i;
469     for (i = 0; i < 8; i++)
470         SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
471     SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
472     SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
473     /* current font */
474     SET_IVT(0x1f, GET_FARVAR(seg, info->font0_seg)
475             , GET_FARVAR(seg, info->font0_off));
476     SET_IVT(0x43, GET_FARVAR(seg, info->font1_seg)
477             , GET_FARVAR(seg, info->font1_off));
478 }
479
480
481 /****************************************************************
482  * VGA int 10 handler
483  ****************************************************************/
484
485 static void
486 handle_1000(struct bregs *regs)
487 {
488     // XXX - inline
489     biosfn_set_video_mode(regs->al);
490     switch(regs->al & 0x7F) {
491     case 6:
492         regs->al = 0x3F;
493         break;
494     case 0:
495     case 1:
496     case 2:
497     case 3:
498     case 4:
499     case 5:
500     case 7:
501         regs->al = 0x30;
502         break;
503     default:
504         regs->al = 0x20;
505     }
506 }
507
508 static void
509 handle_1001(struct bregs *regs)
510 {
511     biosfn_set_cursor_shape(regs->ch, regs->cl);
512 }
513
514 static void
515 handle_1002(struct bregs *regs)
516 {
517     biosfn_set_cursor_pos(regs->bh, regs->dx);
518 }
519
520 static void
521 handle_1003(struct bregs *regs)
522 {
523     regs->cx = biosfn_get_cursor_shape(regs->bh);
524     regs->dx = biosfn_get_cursor_pos(regs->bh);
525 }
526
527 // Read light pen pos (unimplemented)
528 static void
529 handle_1004(struct bregs *regs)
530 {
531     debug_stub(regs);
532     regs->ax = regs->bx = regs->cx = regs->dx = 0;
533 }
534
535 static void
536 handle_1005(struct bregs *regs)
537 {
538     biosfn_set_active_page(regs->al);
539 }
540
541 static void
542 handle_1006(struct bregs *regs)
543 {
544     biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
545                   , 0xFF, SCROLL_UP);
546 }
547
548 static void
549 handle_1007(struct bregs *regs)
550 {
551     biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
552                   , 0xFF, SCROLL_DOWN);
553 }
554
555 static void
556 handle_1008(struct bregs *regs)
557 {
558     // XXX - inline
559     biosfn_read_char_attr(regs->bh, &regs->ax);
560 }
561
562 static void
563 handle_1009(struct bregs *regs)
564 {
565     // XXX - inline
566     biosfn_write_char_attr(regs->al, regs->bh, regs->bl, regs->cx);
567 }
568
569 static void
570 handle_100a(struct bregs *regs)
571 {
572     // XXX - inline
573     biosfn_write_char_only(regs->al, regs->bh, regs->bl, regs->cx);
574 }
575
576
577 static void
578 handle_100b00(struct bregs *regs)
579 {
580     vgahw_set_border_color(regs->bl);
581 }
582
583 static void
584 handle_100b01(struct bregs *regs)
585 {
586     vgahw_set_palette(regs->bl);
587 }
588
589 static void
590 handle_100bXX(struct bregs *regs)
591 {
592     debug_stub(regs);
593 }
594
595 static void
596 handle_100b(struct bregs *regs)
597 {
598     switch (regs->bh) {
599     case 0x00: handle_100b00(regs); break;
600     case 0x01: handle_100b01(regs); break;
601     default:   handle_100bXX(regs); break;
602     }
603 }
604
605
606 static void
607 handle_100c(struct bregs *regs)
608 {
609     // XXX - inline
610     biosfn_write_pixel(regs->bh, regs->al, regs->cx, regs->dx);
611 }
612
613 static void
614 handle_100d(struct bregs *regs)
615 {
616     // XXX - inline
617     biosfn_read_pixel(regs->bh, regs->cx, regs->dx, &regs->ax);
618 }
619
620 static void
621 handle_100e(struct bregs *regs)
622 {
623     // Ralf Brown Interrupt list is WRONG on bh(page)
624     // We do output only on the current page !
625     biosfn_write_teletype(regs->al, 0xff, regs->bl, NO_ATTR);
626 }
627
628 static void
629 handle_100f(struct bregs *regs)
630 {
631     regs->bh = GET_BDA(video_page);
632     regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
633     regs->ah = GET_BDA(video_cols);
634 }
635
636
637 static void
638 handle_101000(struct bregs *regs)
639 {
640     if (regs->bl > 0x14)
641         return;
642     vgahw_set_single_palette_reg(regs->bl, regs->bh);
643 }
644
645 static void
646 handle_101001(struct bregs *regs)
647 {
648     vgahw_set_overscan_border_color(regs->bh);
649 }
650
651 static void
652 handle_101002(struct bregs *regs)
653 {
654     vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
655 }
656
657 static void
658 handle_101003(struct bregs *regs)
659 {
660     vgahw_toggle_intensity(regs->bl);
661 }
662
663 static void
664 handle_101007(struct bregs *regs)
665 {
666     if (regs->bl > 0x14)
667         return;
668     regs->bh = vgahw_get_single_palette_reg(regs->bl);
669 }
670
671 static void
672 handle_101008(struct bregs *regs)
673 {
674     regs->bh = vgahw_get_overscan_border_color(regs);
675 }
676
677 static void
678 handle_101009(struct bregs *regs)
679 {
680     vgahw_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
681 }
682
683 static void
684 handle_101010(struct bregs *regs)
685 {
686     u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
687     vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
688 }
689
690 static void
691 handle_101012(struct bregs *regs)
692 {
693     vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
694 }
695
696 static void
697 handle_101013(struct bregs *regs)
698 {
699     vgahw_select_video_dac_color_page(regs->bl, regs->bh);
700 }
701
702 static void
703 handle_101015(struct bregs *regs)
704 {
705     u8 rgb[3];
706     vgahw_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
707     regs->dh = rgb[0];
708     regs->ch = rgb[1];
709     regs->cl = rgb[2];
710 }
711
712 static void
713 handle_101017(struct bregs *regs)
714 {
715     vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
716 }
717
718 static void
719 handle_101018(struct bregs *regs)
720 {
721     vgahw_set_pel_mask(regs->bl);
722 }
723
724 static void
725 handle_101019(struct bregs *regs)
726 {
727     regs->bl = vgahw_get_pel_mask();
728 }
729
730 static void
731 handle_10101a(struct bregs *regs)
732 {
733     vgahw_read_video_dac_state(&regs->bl, &regs->bh);
734 }
735
736 static void
737 handle_10101b(struct bregs *regs)
738 {
739     biosfn_perform_gray_scale_summing(regs->bx, regs->cx);
740 }
741
742 static void
743 handle_1010XX(struct bregs *regs)
744 {
745     debug_stub(regs);
746 }
747
748 static void
749 handle_1010(struct bregs *regs)
750 {
751     switch (regs->al) {
752     case 0x00: handle_101000(regs); break;
753     case 0x01: handle_101001(regs); break;
754     case 0x02: handle_101002(regs); break;
755     case 0x03: handle_101003(regs); break;
756     case 0x07: handle_101007(regs); break;
757     case 0x08: handle_101008(regs); break;
758     case 0x09: handle_101009(regs); break;
759     case 0x10: handle_101010(regs); break;
760     case 0x12: handle_101012(regs); break;
761     case 0x13: handle_101013(regs); break;
762     case 0x15: handle_101015(regs); break;
763     case 0x17: handle_101017(regs); break;
764     case 0x18: handle_101018(regs); break;
765     case 0x19: handle_101019(regs); break;
766     case 0x1a: handle_10101a(regs); break;
767     case 0x1b: handle_10101b(regs); break;
768     default:   handle_1010XX(regs); break;
769     }
770 }
771
772
773 static void
774 handle_101100(struct bregs *regs)
775 {
776     vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
777                     , regs->dx, regs->bl, regs->bh);
778 }
779
780 static void
781 handle_101101(struct bregs *regs)
782 {
783     vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
784 }
785
786 static void
787 handle_101102(struct bregs *regs)
788 {
789     vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
790 }
791
792 static void
793 handle_101103(struct bregs *regs)
794 {
795     vgahw_set_text_block_specifier(regs->bl);
796 }
797
798 static void
799 handle_101104(struct bregs *regs)
800 {
801     vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
802 }
803
804 static void
805 handle_101110(struct bregs *regs)
806 {
807     vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
808                     , regs->dx, regs->bl, regs->bh);
809     set_scan_lines(regs->bh);
810 }
811
812 static void
813 handle_101111(struct bregs *regs)
814 {
815     vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
816     set_scan_lines(14);
817 }
818
819 static void
820 handle_101112(struct bregs *regs)
821 {
822     vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
823     set_scan_lines(8);
824 }
825
826 static void
827 handle_101114(struct bregs *regs)
828 {
829     vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
830     set_scan_lines(16);
831 }
832
833 static void
834 handle_101130(struct bregs *regs)
835 {
836     switch (regs->bh) {
837     case 0x00: {
838         u32 segoff = GET_IVT(0x1f).segoff;
839         regs->es = segoff >> 16;
840         regs->bp = segoff;
841         break;
842     }
843     case 0x01: {
844         u32 segoff = GET_IVT(0x43).segoff;
845         regs->es = segoff >> 16;
846         regs->bp = segoff;
847         break;
848     }
849     case 0x02:
850         regs->es = get_global_seg();
851         regs->bp = (u32)vgafont14;
852         break;
853     case 0x03:
854         regs->es = get_global_seg();
855         regs->bp = (u32)vgafont8;
856         break;
857     case 0x04:
858         regs->es = get_global_seg();
859         regs->bp = (u32)vgafont8 + 128 * 8;
860         break;
861     case 0x05:
862         regs->es = get_global_seg();
863         regs->bp = (u32)vgafont14alt;
864         break;
865     case 0x06:
866         regs->es = get_global_seg();
867         regs->bp = (u32)vgafont16;
868         break;
869     case 0x07:
870         regs->es = get_global_seg();
871         regs->bp = (u32)vgafont16alt;
872         break;
873     default:
874         dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
875         return;
876     }
877     // Set byte/char of on screen font
878     regs->cx = GET_BDA(char_height) & 0xff;
879
880     // Set Highest char row
881     regs->dx = GET_BDA(video_rows);
882 }
883
884 static void
885 handle_1011XX(struct bregs *regs)
886 {
887     debug_stub(regs);
888 }
889
890 static void
891 handle_1011(struct bregs *regs)
892 {
893     switch (regs->al) {
894     case 0x00: handle_101100(regs); break;
895     case 0x01: handle_101101(regs); break;
896     case 0x02: handle_101102(regs); break;
897     case 0x03: handle_101103(regs); break;
898     case 0x04: handle_101104(regs); break;
899     case 0x10: handle_101110(regs); break;
900     case 0x11: handle_101111(regs); break;
901     case 0x12: handle_101112(regs); break;
902     case 0x14: handle_101114(regs); break;
903     case 0x30: handle_101130(regs); break;
904     default:   handle_1011XX(regs); break;
905     }
906 }
907
908
909 static void
910 handle_101210(struct bregs *regs)
911 {
912     u16 crtc_addr = GET_BDA(crtc_address);
913     if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
914         regs->bx = 0x0103;
915     else
916         regs->bx = 0x0003;
917     regs->cx = GET_BDA(video_switches) & 0x0f;
918 }
919
920 static void
921 handle_101230(struct bregs *regs)
922 {
923     u8 mctl = GET_BDA(modeset_ctl);
924     u8 vswt = GET_BDA(video_switches);
925     switch (regs->al) {
926     case 0x00:
927         // 200 lines
928         mctl = (mctl & ~0x10) | 0x80;
929         vswt = (vswt & ~0x0f) | 0x08;
930         break;
931     case 0x01:
932         // 350 lines
933         mctl &= ~0x90;
934         vswt = (vswt & ~0x0f) | 0x09;
935         break;
936     case 0x02:
937         // 400 lines
938         mctl = (mctl & ~0x80) | 0x10;
939         vswt = (vswt & ~0x0f) | 0x09;
940         break;
941     default:
942         dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
943         break;
944     }
945     SET_BDA(modeset_ctl, mctl);
946     SET_BDA(video_switches, vswt);
947     regs->al = 0x12;
948 }
949
950 static void
951 handle_101231(struct bregs *regs)
952 {
953     u8 v = (regs->al & 0x01) << 3;
954     u8 mctl = GET_BDA(video_ctl) & ~0x08;
955     SET_BDA(video_ctl, mctl | v);
956     regs->al = 0x12;
957 }
958
959 static void
960 handle_101232(struct bregs *regs)
961 {
962     vgahw_enable_video_addressing(regs->al);
963     regs->al = 0x12;
964 }
965
966 static void
967 handle_101233(struct bregs *regs)
968 {
969     u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
970     u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
971     SET_BDA(modeset_ctl, v | v2);
972     regs->al = 0x12;
973 }
974
975 static void
976 handle_101234(struct bregs *regs)
977 {
978     u8 v = (regs->al & 0x01) ^ 0x01;
979     u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
980     SET_BDA(modeset_ctl, v | v2);
981     regs->al = 0x12;
982 }
983
984 static void
985 handle_101235(struct bregs *regs)
986 {
987     debug_stub(regs);
988     regs->al = 0x12;
989 }
990
991 static void
992 handle_101236(struct bregs *regs)
993 {
994     debug_stub(regs);
995     regs->al = 0x12;
996 }
997
998 static void
999 handle_1012XX(struct bregs *regs)
1000 {
1001     debug_stub(regs);
1002 }
1003
1004 static void
1005 handle_1012(struct bregs *regs)
1006 {
1007     switch (regs->bl) {
1008     case 0x10: handle_101210(regs); break;
1009     case 0x30: handle_101230(regs); break;
1010     case 0x31: handle_101231(regs); break;
1011     case 0x32: handle_101232(regs); break;
1012     case 0x33: handle_101233(regs); break;
1013     case 0x34: handle_101234(regs); break;
1014     case 0x35: handle_101235(regs); break;
1015     case 0x36: handle_101236(regs); break;
1016     default:   handle_1012XX(regs); break;
1017     }
1018
1019     // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
1020 }
1021
1022
1023 static void
1024 handle_1013(struct bregs *regs)
1025 {
1026     // XXX - inline
1027     biosfn_write_string(regs->al, regs->bh, regs->bl, regs->cx
1028                         , regs->dh, regs->dl, regs->es, (void*)(regs->bp + 0));
1029 }
1030
1031
1032 static void
1033 handle_101a00(struct bregs *regs)
1034 {
1035     regs->bx = GET_BDA(dcc_index);
1036     regs->al = 0x1a;
1037 }
1038
1039 static void
1040 handle_101a01(struct bregs *regs)
1041 {
1042     SET_BDA(dcc_index, regs->bl);
1043     dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
1044     regs->al = 0x1a;
1045 }
1046
1047 static void
1048 handle_101aXX(struct bregs *regs)
1049 {
1050     debug_stub(regs);
1051 }
1052
1053 static void
1054 handle_101a(struct bregs *regs)
1055 {
1056     switch (regs->al) {
1057     case 0x00: handle_101a00(regs); break;
1058     case 0x01: handle_101a01(regs); break;
1059     default:   handle_101aXX(regs); break;
1060     }
1061 }
1062
1063
1064 struct funcInfo {
1065     u16 static_functionality_off;
1066     u16 static_functionality_seg;
1067     u8 bda_0x49[30];
1068     u8 bda_0x84[3];
1069     u8 dcc_index;
1070     u8 dcc_alt;
1071     u16 colors;
1072     u8 pages;
1073     u8 scan_lines;
1074     u8 primary_char;
1075     u8 secondar_char;
1076     u8 misc;
1077     u8 non_vga_mode;
1078     u8 reserved_2f[2];
1079     u8 video_mem;
1080     u8 save_flags;
1081     u8 disp_info;
1082     u8 reserved_34[12];
1083 };
1084
1085 static void
1086 handle_101b(struct bregs *regs)
1087 {
1088     u16 seg = regs->es;
1089     struct funcInfo *info = (void*)(regs->di+0);
1090     memset_far(seg, info, 0, sizeof(*info));
1091     // Address of static functionality table
1092     SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
1093     SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
1094
1095     // Hard coded copy from BIOS area. Should it be cleaner ?
1096     memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49, 30);
1097     memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84, 3);
1098
1099     SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
1100     SET_FARVAR(seg, info->colors, 16);
1101     SET_FARVAR(seg, info->pages, 8);
1102     SET_FARVAR(seg, info->scan_lines, 2);
1103     SET_FARVAR(seg, info->video_mem, 3);
1104     regs->al = 0x1B;
1105 }
1106
1107
1108 static void
1109 handle_101c00(struct bregs *regs)
1110 {
1111     u16 flags = regs->cx;
1112     u16 size = 0;
1113     if (flags & 1)
1114         size += sizeof(struct saveVideoHardware);
1115     if (flags & 2)
1116         size += sizeof(struct saveBDAstate);
1117     if (flags & 4)
1118         size += sizeof(struct saveDACcolors);
1119     regs->bx = size;
1120     regs->al = 0x1c;
1121 }
1122
1123 static void
1124 handle_101c01(struct bregs *regs)
1125 {
1126     u16 flags = regs->cx;
1127     u16 seg = regs->es;
1128     void *data = (void*)(regs->bx+0);
1129     if (flags & 1) {
1130         vgahw_save_state(seg, data);
1131         data += sizeof(struct saveVideoHardware);
1132     }
1133     if (flags & 2) {
1134         biosfn_save_bda_state(seg, data);
1135         data += sizeof(struct saveBDAstate);
1136     }
1137     if (flags & 4)
1138         vgahw_save_dac_state(seg, data);
1139     regs->al = 0x1c;
1140 }
1141
1142 static void
1143 handle_101c02(struct bregs *regs)
1144 {
1145     u16 flags = regs->cx;
1146     u16 seg = regs->es;
1147     void *data = (void*)(regs->bx+0);
1148     if (flags & 1) {
1149         vgahw_restore_state(seg, data);
1150         data += sizeof(struct saveVideoHardware);
1151     }
1152     if (flags & 2) {
1153         biosfn_restore_bda_state(seg, data);
1154         data += sizeof(struct saveBDAstate);
1155     }
1156     if (flags & 4)
1157         vgahw_restore_dac_state(seg, data);
1158     regs->al = 0x1c;
1159 }
1160
1161 static void
1162 handle_101cXX(struct bregs *regs)
1163 {
1164     debug_stub(regs);
1165 }
1166
1167 static void
1168 handle_101c(struct bregs *regs)
1169 {
1170     switch (regs->al) {
1171     case 0x00: handle_101c00(regs); break;
1172     case 0x01: handle_101c01(regs); break;
1173     case 0x02: handle_101c02(regs); break;
1174     default:   handle_101cXX(regs); break;
1175     }
1176 }
1177
1178
1179 static void
1180 handle_104f00(struct bregs *regs)
1181 {
1182     // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
1183     // XXX - OR cirrus_vesa_00h
1184 }
1185
1186 static void
1187 handle_104f01(struct bregs *regs)
1188 {
1189     // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
1190     // XXX - OR cirrus_vesa_01h
1191 }
1192
1193 static void
1194 handle_104f02(struct bregs *regs)
1195 {
1196     // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
1197     // XXX - OR cirrus_vesa_02h
1198 }
1199
1200 static void
1201 handle_104f03(struct bregs *regs)
1202 {
1203     // XXX - vbe_biosfn_return_current_mode
1204     // XXX - OR cirrus_vesa_03h
1205 }
1206
1207 static void
1208 handle_104f04(struct bregs *regs)
1209 {
1210     // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
1211 }
1212
1213 static void
1214 handle_104f05(struct bregs *regs)
1215 {
1216     // XXX - vbe_biosfn_display_window_control
1217     // XXX - OR cirrus_vesa_05h
1218 }
1219
1220 static void
1221 handle_104f06(struct bregs *regs)
1222 {
1223     // XXX - vbe_biosfn_set_get_logical_scan_line_length
1224     // XXX - OR cirrus_vesa_06h
1225 }
1226
1227 static void
1228 handle_104f07(struct bregs *regs)
1229 {
1230     // XXX - vbe_biosfn_set_get_display_start
1231     // XXX - OR cirrus_vesa_07h
1232 }
1233
1234 static void
1235 handle_104f08(struct bregs *regs)
1236 {
1237     // XXX - vbe_biosfn_set_get_dac_palette_format
1238 }
1239
1240 static void
1241 handle_104f0a(struct bregs *regs)
1242 {
1243     // XXX - vbe_biosfn_return_protected_mode_interface
1244 }
1245
1246 static void
1247 handle_104fXX(struct bregs *regs)
1248 {
1249     debug_stub(regs);
1250     regs->ax = 0x0100;
1251 }
1252
1253 static void
1254 handle_104f(struct bregs *regs)
1255 {
1256     if (! CONFIG_VBE || !vbe_has_vbe_display()) {
1257         handle_104fXX(regs);
1258         return;
1259     }
1260
1261     switch (regs->al) {
1262     case 0x00: handle_104f00(regs); break;
1263     case 0x01: handle_104f01(regs); break;
1264     case 0x02: handle_104f02(regs); break;
1265     case 0x03: handle_104f03(regs); break;
1266     case 0x04: handle_104f04(regs); break;
1267     case 0x05: handle_104f05(regs); break;
1268     case 0x06: handle_104f06(regs); break;
1269     case 0x07: handle_104f07(regs); break;
1270     case 0x08: handle_104f08(regs); break;
1271     case 0x0a: handle_104f0a(regs); break;
1272     default:   handle_104fXX(regs); break;
1273     }
1274 }
1275
1276
1277 static void
1278 handle_10XX(struct bregs *regs)
1279 {
1280     debug_stub(regs);
1281 }
1282
1283 // INT 10h Video Support Service Entry Point
1284 void VISIBLE16
1285 handle_10(struct bregs *regs)
1286 {
1287     debug_enter(regs, DEBUG_VGA_10);
1288     switch (regs->ah) {
1289     case 0x00: handle_1000(regs); break;
1290     case 0x01: handle_1001(regs); break;
1291     case 0x02: handle_1002(regs); break;
1292     case 0x03: handle_1003(regs); break;
1293     case 0x04: handle_1004(regs); break;
1294     case 0x05: handle_1005(regs); break;
1295     case 0x06: handle_1006(regs); break;
1296     case 0x07: handle_1007(regs); break;
1297     case 0x08: handle_1008(regs); break;
1298     case 0x09: handle_1009(regs); break;
1299     case 0x0a: handle_100a(regs); break;
1300     case 0x0b: handle_100b(regs); break;
1301     case 0x0c: handle_100c(regs); break;
1302     case 0x0d: handle_100d(regs); break;
1303     case 0x0e: handle_100e(regs); break;
1304     case 0x0f: handle_100f(regs); break;
1305     case 0x10: handle_1010(regs); break;
1306     case 0x11: handle_1011(regs); break;
1307     case 0x12: handle_1012(regs); break;
1308     case 0x13: handle_1013(regs); break;
1309     case 0x1a: handle_101a(regs); break;
1310     case 0x1b: handle_101b(regs); break;
1311     case 0x1c: handle_101c(regs); break;
1312     case 0x4f: handle_104f(regs); break;
1313     default:   handle_10XX(regs); break;
1314     }
1315 }
1316
1317
1318 /****************************************************************
1319  * VGA post
1320  ****************************************************************/
1321
1322 static void
1323 init_bios_area()
1324 {
1325     // init detected hardware BIOS Area
1326     // set 80x25 color (not clear from RBIL but usual)
1327     u16 eqf = GET_BDA(equipment_list_flags);
1328     SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1329
1330     // Just for the first int10 find its children
1331
1332     // the default char height
1333     SET_BDA(char_height, 0x10);
1334
1335     // Clear the screen
1336     SET_BDA(video_ctl, 0x60);
1337
1338     // Set the basic screen we have
1339     SET_BDA(video_switches, 0xf9);
1340
1341     // Set the basic modeset options
1342     SET_BDA(modeset_ctl, 0x51);
1343
1344     // Set the  default MSR
1345     SET_BDA(video_msr, 0x09);
1346 }
1347
1348 void VISIBLE16
1349 vga_post(struct bregs *regs)
1350 {
1351     debug_enter(regs, DEBUG_VGA_POST);
1352
1353     vgahw_init();
1354
1355     init_bios_area();
1356
1357     if (CONFIG_VBE)
1358         vbe_init();
1359
1360     extern void entry_10(void);
1361     SET_IVT(0x10, get_global_seg(), (u32)entry_10);
1362
1363     if (CONFIG_CIRRUS)
1364         cirrus_init();
1365
1366     // XXX - clear screen and display info
1367
1368     // XXX: fill it
1369     SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
1370     SET_VGA(video_save_pointer_table[1], get_global_seg());
1371
1372     // Fixup checksum
1373     extern u8 _rom_header_size, _rom_header_checksum;
1374     SET_VGA(_rom_header_checksum, 0);
1375     u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
1376     SET_VGA(_rom_header_checksum, sum);
1377 }