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