blob: b1ba01b7b379500b3690189442ad9440b79d256c [file] [log] [blame]
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001// 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:
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040010// * review correctness of converted asm by comparing with RBIL
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040011// * refactor redundant code into sub-functions
12// * See if there is a method to the in/out stuff that can be encapsulated.
13// * remove "biosfn" prefixes
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040014// * verify all funcs static
15//
Kevin O'Connor6ace78f2009-05-14 19:24:49 -040016// * convert vbe/clext code
17//
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040018// * extract hw code from bios interfaces
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040019
20#include "bregs.h" // struct bregs
21#include "biosvar.h" // GET_BDA
22#include "util.h" // memset
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040023#include "vgatables.h" // find_vga_entry
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040024
25// XXX
26#define CONFIG_VBE 0
27#define CONFIG_CIRRUS 0
28
29// XXX
30#define DEBUG_VGA_POST 1
31#define DEBUG_VGA_10 3
32
Kevin O'Connord113a992009-05-16 21:05:02 -040033#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040034
35
36// ===================================================================
37//
38// Video Utils
39//
40// ===================================================================
41
42// -------------------------------------------------------------------
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040043inline void
44call16_vgaint(u32 eax, u32 ebx)
45{
46 asm volatile(
47 "int $0x10\n"
48 "cli\n"
49 "cld"
50 :
51 : "a"(eax), "b"(ebx)
52 : "cc", "memory");
53}
54
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040055
56// ===================================================================
57//
58// BIOS functions
59//
60// ===================================================================
61
62// -------------------------------------------------------------------
63static void
64biosfn_perform_gray_scale_summing(u16 start, u16 count)
65{
Kevin O'Connora0ecb052009-05-18 23:34:00 -040066 vgahw_screen_disable();
Kevin O'Connordd2be772009-05-16 15:41:23 -040067 int i;
68 for (i = start; i < start+count; i++) {
Kevin O'Connora0ecb052009-05-18 23:34:00 -040069 u8 rgb[3];
70 vgahw_get_dac_regs(GET_SEG(SS), rgb, i, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040071
72 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
Kevin O'Connora0ecb052009-05-18 23:34:00 -040073 u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
Kevin O'Connordd2be772009-05-16 15:41:23 -040074 if (intensity > 0x3f)
75 intensity = 0x3f;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040076
Kevin O'Connora0ecb052009-05-18 23:34:00 -040077 vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040078 }
Kevin O'Connora0ecb052009-05-18 23:34:00 -040079 vgahw_screen_enable();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040080}
81
82// -------------------------------------------------------------------
83static void
84biosfn_set_cursor_shape(u8 CH, u8 CL)
85{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040086 CH &= 0x3f;
87 CL &= 0x1f;
88
Kevin O'Connordd2be772009-05-16 15:41:23 -040089 u16 curs = (CH << 8) + CL;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040090 SET_BDA(cursor_type, curs);
91
Kevin O'Connordd2be772009-05-16 15:41:23 -040092 u8 modeset_ctl = GET_BDA(modeset_ctl);
93 u16 cheight = GET_BDA(char_height);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040094 if ((modeset_ctl & 0x01) && (cheight > 8) && (CL < 8) && (CH < 0x20)) {
Kevin O'Connordd2be772009-05-16 15:41:23 -040095 if (CL != (CH + 1))
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040096 CH = ((CH + 1) * cheight / 8) - 1;
Kevin O'Connordd2be772009-05-16 15:41:23 -040097 else
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040098 CH = ((CL + 1) * cheight / 8) - 2;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040099 CL = ((CL + 1) * cheight / 8) - 1;
100 }
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400101 vgahw_set_cursor_shape(CH, CL);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400102}
103
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400104static u16
105biosfn_get_cursor_shape(u8 page)
106{
107 if (page > 7)
108 return 0;
109 // FIXME should handle VGA 14/16 lines
110 return GET_BDA(cursor_type);
111}
112
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400113// -------------------------------------------------------------------
114static void
115biosfn_set_cursor_pos(u8 page, u16 cursor)
116{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400117 // Should not happen...
118 if (page > 7)
119 return;
120
121 // Bios cursor pos
122 SET_BDA(cursor_pos[page], cursor);
123
124 // Set the hardware cursor
Kevin O'Connordd2be772009-05-16 15:41:23 -0400125 u8 current = GET_BDA(video_page);
126 if (page != current)
127 return;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400128
Kevin O'Connordd2be772009-05-16 15:41:23 -0400129 // Get the dimensions
130 u16 nbcols = GET_BDA(video_cols);
131 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400132
Kevin O'Connordd2be772009-05-16 15:41:23 -0400133 u8 xcurs = cursor & 0x00ff;
134 u8 ycurs = (cursor & 0xff00) >> 8;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400135
Kevin O'Connordd2be772009-05-16 15:41:23 -0400136 // Calculate the address knowing nbcols nbrows and page num
137 u16 address = SCREEN_IO_START(nbcols, nbrows, page) + xcurs + ycurs * nbcols;
138
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400139 vgahw_set_cursor_pos(address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400140}
141
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400142u16
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400143biosfn_get_cursor_pos(u8 page)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400144{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400145 if (page > 7)
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400146 return 0;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400147 // FIXME should handle VGA 14/16 lines
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400148 return GET_BDA(cursor_pos[page]);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400149}
150
151// -------------------------------------------------------------------
152static void
153biosfn_set_active_page(u8 page)
154{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400155 if (page > 7)
156 return;
157
158 // Get the mode
Kevin O'Connor5727c292009-05-16 17:29:32 -0400159 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
160 if (!vmode_g)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400161 return;
162
163 // Get pos curs pos for the right page
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400164 u16 cursor = biosfn_get_cursor_pos(page);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400165
Kevin O'Connordd2be772009-05-16 15:41:23 -0400166 u16 address;
Kevin O'Connor5727c292009-05-16 17:29:32 -0400167 if (GET_GLOBAL(vmode_g->class) == TEXT) {
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400168 // Get the dimensions
Kevin O'Connordd2be772009-05-16 15:41:23 -0400169 u16 nbcols = GET_BDA(video_cols);
170 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400171
172 // Calculate the address knowing nbcols nbrows and page num
173 address = SCREEN_MEM_START(nbcols, nbrows, page);
174 SET_BDA(video_pagestart, address);
175
176 // Start address
177 address = SCREEN_IO_START(nbcols, nbrows, page);
178 } else {
Kevin O'Connor5727c292009-05-16 17:29:32 -0400179 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
180 address = page * GET_GLOBAL(vparam_g->slength);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400181 }
182
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400183 vgahw_set_active_page(address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400184
185 // And change the BIOS page
186 SET_BDA(video_page, page);
187
Kevin O'Connora12c2152009-05-13 22:06:16 -0400188 dprintf(1, "Set active page %02x address %04x\n", page, address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400189
190 // Display the cursor, now the page is active
191 biosfn_set_cursor_pos(page, cursor);
192}
193
194static void
195biosfn_set_video_mode(u8 mode)
196{ // mode: Bit 7 is 1 if no clear screen
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400197 if (CONFIG_CIRRUS)
198 cirrus_set_video_mode(mode);
199
Kevin O'Connor21079f42009-05-16 21:30:10 -0400200 if (CONFIG_VBE)
201 if (vbe_has_vbe_display())
202 dispi_set_enable(VBE_DISPI_DISABLED);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400203
204 // The real mode
Kevin O'Connordd2be772009-05-16 15:41:23 -0400205 u8 noclearmem = mode & 0x80;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400206 mode = mode & 0x7f;
207
208 // find the entry in the video modes
Kevin O'Connor5727c292009-05-16 17:29:32 -0400209 struct vgamode_s *vmode_g = find_vga_entry(mode);
210 dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
211 if (!vmode_g)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400212 return;
213
Kevin O'Connor5727c292009-05-16 17:29:32 -0400214 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
215 u16 twidth = GET_GLOBAL(vparam_g->twidth);
216 u16 theightm1 = GET_GLOBAL(vparam_g->theightm1);
217 u16 cheight = GET_GLOBAL(vparam_g->cheight);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400218
219 // Read the bios mode set control
Kevin O'Connordd2be772009-05-16 15:41:23 -0400220 u8 modeset_ctl = GET_BDA(modeset_ctl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400221
222 // Then we know the number of lines
223// FIXME
224
225 // if palette loading (bit 3 of modeset ctl = 0)
226 if ((modeset_ctl & 0x08) == 0) { // Set the PEL mask
Kevin O'Connor5727c292009-05-16 17:29:32 -0400227 outb(GET_GLOBAL(vmode_g->pelmask), VGAREG_PEL_MASK);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400228
229 // Set the whole dac always, from 0
230 outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
231
232 // From which palette
Kevin O'Connor5727c292009-05-16 17:29:32 -0400233 u8 *palette_g = GET_GLOBAL(vmode_g->dac);
Kevin O'Connor3c3c8312009-05-17 16:16:29 -0400234 u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400235 // Always 256*3 values
Kevin O'Connordd2be772009-05-16 15:41:23 -0400236 u16 i;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400237 for (i = 0; i < 0x0100; i++) {
Kevin O'Connor3c3c8312009-05-17 16:16:29 -0400238 if (i < palsize) {
Kevin O'Connordd2be772009-05-16 15:41:23 -0400239 outb(GET_GLOBAL(palette_g[(i * 3) + 0]), VGAREG_DAC_DATA);
240 outb(GET_GLOBAL(palette_g[(i * 3) + 1]), VGAREG_DAC_DATA);
241 outb(GET_GLOBAL(palette_g[(i * 3) + 2]), VGAREG_DAC_DATA);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400242 } else {
243 outb(0, VGAREG_DAC_DATA);
244 outb(0, VGAREG_DAC_DATA);
245 outb(0, VGAREG_DAC_DATA);
246 }
247 }
248 if ((modeset_ctl & 0x02) == 0x02)
249 biosfn_perform_gray_scale_summing(0x00, 0x100);
250 }
251 // Reset Attribute Ctl flip-flop
252 inb(VGAREG_ACTL_RESET);
253
254 // Set Attribute Ctl
Kevin O'Connordd2be772009-05-16 15:41:23 -0400255 u16 i;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400256 for (i = 0; i <= 0x13; i++) {
257 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor5727c292009-05-16 17:29:32 -0400258 outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400259 }
260 outb(0x14, VGAREG_ACTL_ADDRESS);
261 outb(0x00, VGAREG_ACTL_WRITE_DATA);
262
263 // Set Sequencer Ctl
264 outb(0, VGAREG_SEQU_ADDRESS);
265 outb(0x03, VGAREG_SEQU_DATA);
266 for (i = 1; i <= 4; i++) {
267 outb(i, VGAREG_SEQU_ADDRESS);
Kevin O'Connor5727c292009-05-16 17:29:32 -0400268 outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400269 }
270
271 // Set Grafx Ctl
272 for (i = 0; i <= 8; i++) {
273 outb(i, VGAREG_GRDC_ADDRESS);
Kevin O'Connor5727c292009-05-16 17:29:32 -0400274 outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400275 }
276
277 // Set CRTC address VGA or MDA
278 u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
Kevin O'Connor5727c292009-05-16 17:29:32 -0400279 if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400280 crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
281
282 // Disable CRTC write protection
283 outw(0x0011, crtc_addr);
284 // Set CRTC regs
285 for (i = 0; i <= 0x18; i++) {
286 outb(i, crtc_addr);
Kevin O'Connor5727c292009-05-16 17:29:32 -0400287 outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400288 }
289
290 // Set the misc register
Kevin O'Connor5727c292009-05-16 17:29:32 -0400291 outb(GET_GLOBAL(vparam_g->miscreg), VGAREG_WRITE_MISC_OUTPUT);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400292
293 // Enable video
294 outb(0x20, VGAREG_ACTL_ADDRESS);
295 inb(VGAREG_ACTL_RESET);
296
297 if (noclearmem == 0x00) {
Kevin O'Connor5727c292009-05-16 17:29:32 -0400298 if (GET_GLOBAL(vmode_g->class) == TEXT) {
299 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400300 } else {
301 if (mode < 0x0d) {
Kevin O'Connor5727c292009-05-16 17:29:32 -0400302 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400303 } else {
304 outb(0x02, VGAREG_SEQU_ADDRESS);
Kevin O'Connordd2be772009-05-16 15:41:23 -0400305 u8 mmask = inb(VGAREG_SEQU_DATA);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400306 outb(0x0f, VGAREG_SEQU_DATA); // all planes
Kevin O'Connor5727c292009-05-16 17:29:32 -0400307 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400308 outb(mmask, VGAREG_SEQU_DATA);
309 }
310 }
311 }
312 // Set the BIOS mem
313 SET_BDA(video_mode, mode);
314 SET_BDA(video_cols, twidth);
Kevin O'Connor5727c292009-05-16 17:29:32 -0400315 SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400316 SET_BDA(crtc_address, crtc_addr);
317 SET_BDA(video_rows, theightm1);
318 SET_BDA(char_height, cheight);
319 SET_BDA(video_ctl, (0x60 | noclearmem));
320 SET_BDA(video_switches, 0xF9);
321 SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
322
323 // FIXME We nearly have the good tables. to be reworked
324 SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
325 SET_BDA(video_savetable_ptr, (u32)video_save_pointer_table);
Kevin O'Connord113a992009-05-16 21:05:02 -0400326 SET_BDA(video_savetable_seg, get_global_seg());
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400327
328 // FIXME
329 SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
330 SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
331
332 // Set cursor shape
Kevin O'Connor5727c292009-05-16 17:29:32 -0400333 if (GET_GLOBAL(vmode_g->class) == TEXT)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400334 biosfn_set_cursor_shape(0x06, 0x07);
335 // Set cursor pos for page 0..7
336 for (i = 0; i < 8; i++)
337 biosfn_set_cursor_pos(i, 0x0000);
338
339 // Set active page 0
340 biosfn_set_active_page(0x00);
341
342 // Write the fonts in memory
Kevin O'Connor5727c292009-05-16 17:29:32 -0400343 if (GET_GLOBAL(vmode_g->class) == TEXT) {
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400344 call16_vgaint(0x1104, 0);
345 call16_vgaint(0x1103, 0);
346 }
347 // Set the ints 0x1F and 0x43
Kevin O'Connord113a992009-05-16 21:05:02 -0400348 SET_IVT(0x1f, get_global_seg(), (u32)&vgafont8[128 * 8]);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400349
350 switch (cheight) {
351 case 8:
Kevin O'Connord113a992009-05-16 21:05:02 -0400352 SET_IVT(0x43, get_global_seg(), (u32)vgafont8);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400353 break;
354 case 14:
Kevin O'Connord113a992009-05-16 21:05:02 -0400355 SET_IVT(0x43, get_global_seg(), (u32)vgafont14);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400356 break;
357 case 16:
Kevin O'Connord113a992009-05-16 21:05:02 -0400358 SET_IVT(0x43, get_global_seg(), (u32)vgafont16);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400359 break;
360 }
361}
362
363// -------------------------------------------------------------------
364static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400365biosfn_write_teletype(u8 car, u8 page, u8 attr, u8 flag)
366{ // flag = WITH_ATTR / NO_ATTR
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400367 // special case if page is 0xff, use current page
368 if (page == 0xff)
369 page = GET_BDA(video_page);
370
371 // Get the mode
Kevin O'Connor5727c292009-05-16 17:29:32 -0400372 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
373 if (!vmode_g)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400374 return;
375
376 // Get the cursor pos for the page
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400377 u16 cursor = biosfn_get_cursor_pos(page);
Kevin O'Connordd2be772009-05-16 15:41:23 -0400378 u8 xcurs = cursor & 0x00ff;
379 u8 ycurs = (cursor & 0xff00) >> 8;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400380
381 // Get the dimensions
Kevin O'Connordd2be772009-05-16 15:41:23 -0400382 u16 nbrows = GET_BDA(video_rows) + 1;
383 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400384
385 switch (car) {
386 case 7:
387 //FIXME should beep
388 break;
389
390 case 8:
391 if (xcurs > 0)
392 xcurs--;
393 break;
394
395 case '\r':
396 xcurs = 0;
397 break;
398
399 case '\n':
400 ycurs++;
401 break;
402
403 case '\t':
404 do {
405 biosfn_write_teletype(' ', page, attr, flag);
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400406 cursor = biosfn_get_cursor_pos(page);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400407 xcurs = cursor & 0x00ff;
408 ycurs = (cursor & 0xff00) >> 8;
409 } while (xcurs % 8 == 0);
410 break;
411
412 default:
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400413 if (flag == WITH_ATTR)
414 biosfn_write_char_attr(car, page, attr, 1);
415 else
416 biosfn_write_char_only(car, page, attr, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400417 xcurs++;
418 }
419
420 // Do we need to wrap ?
421 if (xcurs == nbcols) {
422 xcurs = 0;
423 ycurs++;
424 }
425 // Do we need to scroll ?
426 if (ycurs == nbrows) {
Kevin O'Connor5727c292009-05-16 17:29:32 -0400427 if (GET_GLOBAL(vmode_g->class) == TEXT)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400428 biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, page,
429 SCROLL_UP);
430 else
431 biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, page,
432 SCROLL_UP);
433 ycurs -= 1;
434 }
435 // Set the cursor for the page
436 cursor = ycurs;
437 cursor <<= 8;
438 cursor += xcurs;
439 biosfn_set_cursor_pos(page, cursor);
440}
441
442// -------------------------------------------------------------------
443static void
444biosfn_get_video_mode(struct bregs *regs)
445{
446 regs->bh = GET_BDA(video_page);
447 regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
448 regs->ah = GET_BDA(video_cols);
449}
450
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400451static void
452set_scan_lines(u8 lines)
453{
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400454 vgahw_set_scan_lines(lines);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400455 if (lines == 8)
456 biosfn_set_cursor_shape(0x06, 0x07);
457 else
458 biosfn_set_cursor_shape(lines - 4, lines - 3);
459 SET_BDA(char_height, lines);
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400460 u16 vde = vgahw_get_vde();
Kevin O'Connordd2be772009-05-16 15:41:23 -0400461 u8 rows = vde / lines;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400462 SET_BDA(video_rows, rows - 1);
Kevin O'Connordd2be772009-05-16 15:41:23 -0400463 u16 cols = GET_BDA(video_cols);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400464 SET_BDA(video_pagesize, rows * cols * 2);
465}
466
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400467// -------------------------------------------------------------------
468static void
469biosfn_get_font_info(u8 BH, u16 *ES, u16 *BP, u16 *CX, u16 *DX)
470{
471 switch (BH) {
472 case 0x00: {
473 u32 segoff = GET_IVT(0x1f).segoff;
474 *ES = segoff >> 16;
475 *BP = segoff;
476 break;
477 }
478 case 0x01: {
479 u32 segoff = GET_IVT(0x43).segoff;
480 *ES = segoff >> 16;
481 *BP = segoff;
482 break;
483 }
484 case 0x02:
Kevin O'Connord113a992009-05-16 21:05:02 -0400485 *ES = get_global_seg();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400486 *BP = (u32)vgafont14;
487 break;
488 case 0x03:
Kevin O'Connord113a992009-05-16 21:05:02 -0400489 *ES = get_global_seg();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400490 *BP = (u32)vgafont8;
491 break;
492 case 0x04:
Kevin O'Connord113a992009-05-16 21:05:02 -0400493 *ES = get_global_seg();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400494 *BP = (u32)vgafont8 + 128 * 8;
495 break;
496 case 0x05:
Kevin O'Connord113a992009-05-16 21:05:02 -0400497 *ES = get_global_seg();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400498 *BP = (u32)vgafont14alt;
499 break;
500 case 0x06:
Kevin O'Connord113a992009-05-16 21:05:02 -0400501 *ES = get_global_seg();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400502 *BP = (u32)vgafont16;
503 break;
504 case 0x07:
Kevin O'Connord113a992009-05-16 21:05:02 -0400505 *ES = get_global_seg();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400506 *BP = (u32)vgafont16alt;
507 break;
508 default:
Kevin O'Connora12c2152009-05-13 22:06:16 -0400509 dprintf(1, "Get font info BH(%02x) was discarded\n", BH);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400510 return;
511 }
512 // Set byte/char of on screen font
513 *CX = GET_BDA(char_height) & 0xff;
514
515 // Set Highest char row
516 *DX = GET_BDA(video_rows);
517}
518
519// -------------------------------------------------------------------
520static void
521biosfn_get_ega_info(struct bregs *regs)
522{
523 regs->cx = GET_BDA(video_switches) & 0x0f;
524 regs->ax = GET_BDA(crtc_address);
525 if (regs->ax == VGAREG_MDA_CRTC_ADDRESS)
526 regs->bx = 0x0103;
527 else
528 regs->bx = 0x0003;
529}
530
531// -------------------------------------------------------------------
532static void
533biosfn_select_vert_res(struct bregs *regs)
534{
535 u8 mctl = GET_BDA(modeset_ctl);
536 u8 vswt = GET_BDA(video_switches);
537
538 switch (regs->al) {
539 case 0x00:
540 // 200 lines
541 mctl = (mctl & ~0x10) | 0x80;
542 vswt = (vswt & ~0x0f) | 0x08;
543 break;
544 case 0x01:
545 // 350 lines
546 mctl &= ~0x90;
547 vswt = (vswt & ~0x0f) | 0x09;
548 break;
549 case 0x02:
550 // 400 lines
551 mctl = (mctl & ~0x80) | 0x10;
552 vswt = (vswt & ~0x0f) | 0x09;
553 break;
554 default:
Kevin O'Connora12c2152009-05-13 22:06:16 -0400555 dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400556 break;
557 }
558 SET_BDA(modeset_ctl, mctl);
559 SET_BDA(video_switches, vswt);
560 regs->ax = 0x1212;
561}
562
563static void
564biosfn_enable_default_palette_loading(struct bregs *regs)
565{
566 u8 v = (regs->al & 0x01) << 3;
567 u8 mctl = GET_BDA(video_ctl) & ~0x08;
568 SET_BDA(video_ctl, mctl | v);
569 regs->ax = 0x1212;
570}
571
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400572
573static void
574biosfn_enable_grayscale_summing(struct bregs *regs)
575{
576 u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
577 u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
578 SET_BDA(modeset_ctl, v | v2);
579 regs->ax = 0x1212;
580}
581
582static void
583biosfn_enable_cursor_emulation(struct bregs *regs)
584{
585 u8 v = (regs->al & 0x01) ^ 0x01;
586 u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
587 SET_BDA(modeset_ctl, v | v2);
588 regs->ax = 0x1212;
589}
590
591// -------------------------------------------------------------------
592static void
593biosfn_write_string(u8 flag, u8 page, u8 attr, u16 count, u8 row, u8 col,
Kevin O'Connordd2be772009-05-16 15:41:23 -0400594 u16 seg, u8 *offset_far)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400595{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400596 // Read curs info for the page
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400597 u16 oldcurs = biosfn_get_cursor_pos(page);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400598
599 // if row=0xff special case : use current cursor position
600 if (row == 0xff) {
601 col = oldcurs & 0x00ff;
602 row = (oldcurs & 0xff00) >> 8;
603 }
604
Kevin O'Connordd2be772009-05-16 15:41:23 -0400605 u16 newcurs = row;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400606 newcurs <<= 8;
607 newcurs += col;
608 biosfn_set_cursor_pos(page, newcurs);
609
610 while (count-- != 0) {
Kevin O'Connordd2be772009-05-16 15:41:23 -0400611 u8 car = GET_FARVAR(seg, *offset_far);
612 offset_far++;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400613 if ((flag & 0x02) != 0) {
Kevin O'Connordd2be772009-05-16 15:41:23 -0400614 attr = GET_FARVAR(seg, *offset_far);
615 offset_far++;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400616 }
617
618 biosfn_write_teletype(car, page, attr, WITH_ATTR);
619 }
620
621 // Set back curs pos
622 if ((flag & 0x01) == 0)
623 biosfn_set_cursor_pos(page, oldcurs);
624}
625
626// -------------------------------------------------------------------
627static void
628biosfn_read_display_code(struct bregs *regs)
629{
630 regs->bx = GET_BDA(dcc_index);
631 regs->al = 0x1a;
632}
633
634static void
635biosfn_set_display_code(struct bregs *regs)
636{
637 SET_BDA(dcc_index, regs->bl);
Kevin O'Connora12c2152009-05-13 22:06:16 -0400638 dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400639 regs->al = 0x1a;
640}
641
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400642static void
Kevin O'Connorca668642009-05-21 23:06:08 -0400643biosfn_save_bda_state(u16 seg, struct saveBDAstate *info)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400644{
Kevin O'Connorca668642009-05-21 23:06:08 -0400645 SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
646 SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
647 SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
648 SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
649 SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
650 SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
651 SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
652 SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
653 SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
654 SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
655 u16 i;
656 for (i=0; i<8; i++)
657 SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
658 SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
659 SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
660 /* current font */
661 SET_FARVAR(seg, *(u32*)&info->font0_off, GET_IVT(0x1f).segoff);
662 SET_FARVAR(seg, *(u32*)&info->font1_off, GET_IVT(0x43).segoff);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400663}
664
Kevin O'Connorca668642009-05-21 23:06:08 -0400665static void
666biosfn_restore_bda_state(u16 seg, struct saveBDAstate *info)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400667{
Kevin O'Connorca668642009-05-21 23:06:08 -0400668 SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
669 SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
670 SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
671 SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
672 SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
673 SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
674 SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
675 SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
676 SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
677 SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
678 u16 i;
679 for (i = 0; i < 8; i++)
680 SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
681 SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
682 SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
683 /* current font */
684 SET_IVT(0x1f, GET_FARVAR(seg, info->font0_seg)
685 , GET_FARVAR(seg, info->font0_off));
686 SET_IVT(0x43, GET_FARVAR(seg, info->font1_seg)
687 , GET_FARVAR(seg, info->font1_off));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400688}
689
690
691/****************************************************************
692 * VGA int 10 handler
693 ****************************************************************/
694
695static void
696handle_1000(struct bregs *regs)
697{
698 // XXX - inline
699 biosfn_set_video_mode(regs->al);
700 switch(regs->al & 0x7F) {
701 case 6:
702 regs->al = 0x3F;
703 break;
704 case 0:
705 case 1:
706 case 2:
707 case 3:
708 case 4:
709 case 5:
710 case 7:
711 regs->al = 0x30;
712 break;
713 default:
714 regs->al = 0x20;
715 }
716}
717
718static void
719handle_1001(struct bregs *regs)
720{
721 biosfn_set_cursor_shape(regs->ch, regs->cl);
722}
723
724static void
725handle_1002(struct bregs *regs)
726{
727 biosfn_set_cursor_pos(regs->bh, regs->dx);
728}
729
730static void
731handle_1003(struct bregs *regs)
732{
Kevin O'Connor0818e1a2009-05-16 18:00:19 -0400733 regs->cx = biosfn_get_cursor_shape(regs->bh);
734 regs->dx = biosfn_get_cursor_pos(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400735}
736
737// Read light pen pos (unimplemented)
738static void
739handle_1004(struct bregs *regs)
740{
741 debug_stub(regs);
742 regs->ax = regs->bx = regs->cx = regs->dx = 0;
743}
744
745static void
746handle_1005(struct bregs *regs)
747{
748 biosfn_set_active_page(regs->al);
749}
750
751static void
752handle_1006(struct bregs *regs)
753{
754 biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
755 , 0xFF, SCROLL_UP);
756}
757
758static void
759handle_1007(struct bregs *regs)
760{
761 biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
762 , 0xFF, SCROLL_DOWN);
763}
764
765static void
766handle_1008(struct bregs *regs)
767{
768 // XXX - inline
769 biosfn_read_char_attr(regs->bh, &regs->ax);
770}
771
772static void
773handle_1009(struct bregs *regs)
774{
775 // XXX - inline
776 biosfn_write_char_attr(regs->al, regs->bh, regs->bl, regs->cx);
777}
778
779static void
780handle_100a(struct bregs *regs)
781{
782 // XXX - inline
783 biosfn_write_char_only(regs->al, regs->bh, regs->bl, regs->cx);
784}
785
786
787static void
788handle_100b00(struct bregs *regs)
789{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400790 vgahw_set_border_color(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400791}
792
793static void
794handle_100b01(struct bregs *regs)
795{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400796 vgahw_set_palette(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400797}
798
799static void
800handle_100bXX(struct bregs *regs)
801{
802 debug_stub(regs);
803}
804
805static void
806handle_100b(struct bregs *regs)
807{
808 switch (regs->bh) {
809 case 0x00: handle_100b00(regs); break;
810 case 0x01: handle_100b01(regs); break;
811 default: handle_100bXX(regs); break;
812 }
813}
814
815
816static void
817handle_100c(struct bregs *regs)
818{
819 // XXX - inline
820 biosfn_write_pixel(regs->bh, regs->al, regs->cx, regs->dx);
821}
822
823static void
824handle_100d(struct bregs *regs)
825{
826 // XXX - inline
827 biosfn_read_pixel(regs->bh, regs->cx, regs->dx, &regs->ax);
828}
829
830static void
831handle_100e(struct bregs *regs)
832{
833 // Ralf Brown Interrupt list is WRONG on bh(page)
834 // We do output only on the current page !
835 biosfn_write_teletype(regs->al, 0xff, regs->bl, NO_ATTR);
836}
837
838static void
839handle_100f(struct bregs *regs)
840{
841 // XXX - inline
842 biosfn_get_video_mode(regs);
843}
844
845
846static void
847handle_101000(struct bregs *regs)
848{
849 if (regs->bl > 0x14)
850 return;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400851 vgahw_set_single_palette_reg(regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400852}
853
854static void
855handle_101001(struct bregs *regs)
856{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400857 vgahw_set_overscan_border_color(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400858}
859
860static void
861handle_101002(struct bregs *regs)
862{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400863 vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400864}
865
866static void
867handle_101003(struct bregs *regs)
868{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400869 vgahw_toggle_intensity(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400870}
871
872static void
873handle_101007(struct bregs *regs)
874{
875 if (regs->bl > 0x14)
876 return;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400877 regs->bh = vgahw_get_single_palette_reg(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400878}
879
880static void
881handle_101008(struct bregs *regs)
882{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400883 regs->bh = vgahw_get_overscan_border_color(regs);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400884}
885
886static void
887handle_101009(struct bregs *regs)
888{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400889 vgahw_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400890}
891
892static void
893handle_101010(struct bregs *regs)
894{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400895 u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
896 vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400897}
898
899static void
900handle_101012(struct bregs *regs)
901{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400902 vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400903}
904
905static void
906handle_101013(struct bregs *regs)
907{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400908 vgahw_select_video_dac_color_page(regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400909}
910
911static void
912handle_101015(struct bregs *regs)
913{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400914 u8 rgb[3];
915 vgahw_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
916 regs->dh = rgb[0];
917 regs->ch = rgb[1];
918 regs->cl = rgb[2];
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400919}
920
921static void
922handle_101017(struct bregs *regs)
923{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400924 vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400925}
926
927static void
928handle_101018(struct bregs *regs)
929{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400930 vgahw_set_pel_mask(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400931}
932
933static void
934handle_101019(struct bregs *regs)
935{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400936 regs->bl = vgahw_get_pel_mask();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400937}
938
939static void
940handle_10101a(struct bregs *regs)
941{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400942 vgahw_read_video_dac_state(&regs->bl, &regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400943}
944
945static void
946handle_10101b(struct bregs *regs)
947{
948 biosfn_perform_gray_scale_summing(regs->bx, regs->cx);
949}
950
951static void
952handle_1010XX(struct bregs *regs)
953{
954 debug_stub(regs);
955}
956
957static void
958handle_1010(struct bregs *regs)
959{
960 switch (regs->al) {
961 case 0x00: handle_101000(regs); break;
962 case 0x01: handle_101001(regs); break;
963 case 0x02: handle_101002(regs); break;
964 case 0x03: handle_101003(regs); break;
965 case 0x07: handle_101007(regs); break;
966 case 0x08: handle_101008(regs); break;
967 case 0x09: handle_101009(regs); break;
968 case 0x10: handle_101010(regs); break;
969 case 0x12: handle_101012(regs); break;
970 case 0x13: handle_101013(regs); break;
971 case 0x15: handle_101015(regs); break;
972 case 0x17: handle_101017(regs); break;
973 case 0x18: handle_101018(regs); break;
974 case 0x19: handle_101019(regs); break;
975 case 0x1a: handle_10101a(regs); break;
976 case 0x1b: handle_10101b(regs); break;
977 default: handle_1010XX(regs); break;
978 }
979}
980
981
982static void
983handle_101100(struct bregs *regs)
984{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400985 biosfn_load_text_user_pat(regs->es, regs->bp
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400986 , regs->cx, regs->dx, regs->bl, regs->bh);
987}
988
989static void
990handle_101101(struct bregs *regs)
991{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400992 biosfn_load_text_8_14_pat(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400993}
994
995static void
996handle_101102(struct bregs *regs)
997{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400998 biosfn_load_text_8_8_pat(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400999}
1000
1001static void
1002handle_101103(struct bregs *regs)
1003{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -04001004 vgahw_set_text_block_specifier(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001005}
1006
1007static void
1008handle_101104(struct bregs *regs)
1009{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001010 biosfn_load_text_8_16_pat(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001011}
1012
1013static void
1014handle_101110(struct bregs *regs)
1015{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001016 biosfn_load_text_user_pat(regs->es, regs->bp
1017 , regs->cx, regs->dx, regs->bl, regs->bh);
1018 set_scan_lines(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001019}
1020
1021static void
1022handle_101111(struct bregs *regs)
1023{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001024 biosfn_load_text_8_14_pat(regs->bl);
1025 set_scan_lines(14);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001026}
1027
1028static void
1029handle_101112(struct bregs *regs)
1030{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001031 biosfn_load_text_8_8_pat(regs->bl);
1032 set_scan_lines(8);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001033}
1034
1035static void
1036handle_101114(struct bregs *regs)
1037{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001038 biosfn_load_text_8_16_pat(regs->bl);
1039 set_scan_lines(16);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001040}
1041
1042static void
1043handle_101130(struct bregs *regs)
1044{
1045 // XXX - inline
Kevin O'Connor99e08b72009-05-17 00:07:31 -04001046 biosfn_get_font_info(regs->bh, &regs->es, &regs->bp
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001047 , &regs->cx, &regs->dx);
1048}
1049
1050static void
1051handle_1011XX(struct bregs *regs)
1052{
1053 debug_stub(regs);
1054}
1055
1056static void
1057handle_1011(struct bregs *regs)
1058{
1059 switch (regs->al) {
1060 case 0x00: handle_101100(regs); break;
1061 case 0x01: handle_101101(regs); break;
1062 case 0x02: handle_101102(regs); break;
1063 case 0x03: handle_101103(regs); break;
1064 case 0x04: handle_101104(regs); break;
1065 case 0x10: handle_101110(regs); break;
1066 case 0x11: handle_101111(regs); break;
1067 case 0x12: handle_101112(regs); break;
1068 case 0x14: handle_101114(regs); break;
1069 case 0x30: handle_101130(regs); break;
1070 default: handle_1011XX(regs); break;
1071 }
1072}
1073
1074
1075static void
1076handle_101210(struct bregs *regs)
1077{
1078 // XXX - inline
1079 biosfn_get_ega_info(regs);
1080}
1081
1082static void
1083handle_101230(struct bregs *regs)
1084{
1085 // XXX - inline
1086 biosfn_select_vert_res(regs);
1087}
1088
1089static void
1090handle_101231(struct bregs *regs)
1091{
1092 // XXX - inline
1093 biosfn_enable_default_palette_loading(regs);
1094}
1095
1096static void
1097handle_101232(struct bregs *regs)
1098{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -04001099 vgahw_enable_video_addressing(regs->al);
1100 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001101}
1102
1103static void
1104handle_101233(struct bregs *regs)
1105{
1106 // XXX - inline
1107 biosfn_enable_grayscale_summing(regs);
1108}
1109
1110static void
1111handle_101234(struct bregs *regs)
1112{
1113 // XXX - inline
1114 biosfn_enable_cursor_emulation(regs);
1115}
1116
1117static void
1118handle_101235(struct bregs *regs)
1119{
1120 debug_stub(regs);
1121 regs->al = 0x12;
1122}
1123
1124static void
1125handle_101236(struct bregs *regs)
1126{
1127 debug_stub(regs);
1128 regs->al = 0x12;
1129}
1130
1131static void
1132handle_1012XX(struct bregs *regs)
1133{
1134 debug_stub(regs);
1135}
1136
1137static void
1138handle_1012(struct bregs *regs)
1139{
1140 switch (regs->bl) {
1141 case 0x10: handle_101210(regs); break;
1142 case 0x30: handle_101230(regs); break;
1143 case 0x31: handle_101231(regs); break;
1144 case 0x32: handle_101232(regs); break;
1145 case 0x33: handle_101233(regs); break;
1146 case 0x34: handle_101234(regs); break;
1147 case 0x35: handle_101235(regs); break;
1148 case 0x36: handle_101236(regs); break;
1149 default: handle_1012XX(regs); break;
1150 }
1151
1152 // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
1153}
1154
1155
1156static void
1157handle_1013(struct bregs *regs)
1158{
1159 // XXX - inline
1160 biosfn_write_string(regs->al, regs->bh, regs->bl, regs->cx
Kevin O'Connor99e08b72009-05-17 00:07:31 -04001161 , regs->dh, regs->dl, regs->es, (void*)(regs->bp + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001162}
1163
1164
1165static void
1166handle_101a00(struct bregs *regs)
1167{
1168 // XXX - inline
1169 biosfn_read_display_code(regs);
1170}
1171
1172static void
1173handle_101a01(struct bregs *regs)
1174{
1175 // XXX - inline
1176 biosfn_set_display_code(regs);
1177}
1178
1179static void
1180handle_101aXX(struct bregs *regs)
1181{
1182 debug_stub(regs);
1183}
1184
1185static void
1186handle_101a(struct bregs *regs)
1187{
1188 switch (regs->al) {
1189 case 0x00: handle_101a00(regs); break;
1190 case 0x01: handle_101a01(regs); break;
1191 default: handle_101aXX(regs); break;
1192 }
1193}
1194
1195
Kevin O'Connorca668642009-05-21 23:06:08 -04001196struct funcInfo {
1197 u16 static_functionality_off;
1198 u16 static_functionality_seg;
1199 u8 bda_0x49[30];
1200 u8 bda_0x84[3];
1201 u8 dcc_index;
1202 u8 dcc_alt;
1203 u16 colors;
1204 u8 pages;
1205 u8 scan_lines;
1206 u8 primary_char;
1207 u8 secondar_char;
1208 u8 misc;
1209 u8 non_vga_mode;
1210 u8 reserved_2f[2];
1211 u8 video_mem;
1212 u8 save_flags;
1213 u8 disp_info;
1214 u8 reserved_34[12];
1215};
1216
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001217static void
1218handle_101b(struct bregs *regs)
1219{
Kevin O'Connorca668642009-05-21 23:06:08 -04001220 u16 seg = regs->es;
1221 struct funcInfo *info = (void*)(regs->di+0);
1222 memset_far(seg, info, 0, sizeof(*info));
1223 // Address of static functionality table
1224 SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
1225 SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
1226
1227 // Hard coded copy from BIOS area. Should it be cleaner ?
1228 memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49, 30);
1229 memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84, 3);
1230
1231 SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
1232 SET_FARVAR(seg, info->colors, 16);
1233 SET_FARVAR(seg, info->pages, 8);
1234 SET_FARVAR(seg, info->scan_lines, 2);
1235 SET_FARVAR(seg, info->video_mem, 3);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001236 regs->al = 0x1B;
1237}
1238
1239
1240static void
1241handle_101c00(struct bregs *regs)
1242{
Kevin O'Connorca668642009-05-21 23:06:08 -04001243 u16 flags = regs->cx;
1244 u16 size = 0;
1245 if (flags & 1)
1246 size += sizeof(struct saveVideoHardware);
1247 if (flags & 2)
1248 size += sizeof(struct saveBDAstate);
1249 if (flags & 4)
1250 size += sizeof(struct saveDACcolors);
1251 regs->bx = size;
1252 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001253}
1254
1255static void
1256handle_101c01(struct bregs *regs)
1257{
Kevin O'Connorca668642009-05-21 23:06:08 -04001258 u16 flags = regs->cx;
1259 u16 seg = regs->es;
1260 void *data = (void*)(regs->bx+0);
1261 if (flags & 1) {
1262 vgahw_save_state(seg, data);
1263 data += sizeof(struct saveVideoHardware);
1264 }
1265 if (flags & 2) {
1266 biosfn_save_bda_state(seg, data);
1267 data += sizeof(struct saveBDAstate);
1268 }
1269 if (flags & 4)
1270 vgahw_save_dac_state(seg, data);
1271 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001272}
1273
1274static void
1275handle_101c02(struct bregs *regs)
1276{
Kevin O'Connorca668642009-05-21 23:06:08 -04001277 u16 flags = regs->cx;
1278 u16 seg = regs->es;
1279 void *data = (void*)(regs->bx+0);
1280 if (flags & 1) {
1281 vgahw_restore_state(seg, data);
1282 data += sizeof(struct saveVideoHardware);
1283 }
1284 if (flags & 2) {
1285 biosfn_restore_bda_state(seg, data);
1286 data += sizeof(struct saveBDAstate);
1287 }
1288 if (flags & 4)
1289 vgahw_restore_dac_state(seg, data);
1290 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001291}
1292
1293static void
1294handle_101cXX(struct bregs *regs)
1295{
1296 debug_stub(regs);
1297}
1298
1299static void
1300handle_101c(struct bregs *regs)
1301{
1302 switch (regs->al) {
1303 case 0x00: handle_101c00(regs); break;
1304 case 0x01: handle_101c01(regs); break;
1305 case 0x02: handle_101c02(regs); break;
1306 default: handle_101cXX(regs); break;
1307 }
1308}
1309
1310
1311static void
1312handle_104f00(struct bregs *regs)
1313{
1314 // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
1315 // XXX - OR cirrus_vesa_00h
1316}
1317
1318static void
1319handle_104f01(struct bregs *regs)
1320{
1321 // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
1322 // XXX - OR cirrus_vesa_01h
1323}
1324
1325static void
1326handle_104f02(struct bregs *regs)
1327{
1328 // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
1329 // XXX - OR cirrus_vesa_02h
1330}
1331
1332static void
1333handle_104f03(struct bregs *regs)
1334{
1335 // XXX - vbe_biosfn_return_current_mode
1336 // XXX - OR cirrus_vesa_03h
1337}
1338
1339static void
1340handle_104f04(struct bregs *regs)
1341{
1342 // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
1343}
1344
1345static void
1346handle_104f05(struct bregs *regs)
1347{
1348 // XXX - vbe_biosfn_display_window_control
1349 // XXX - OR cirrus_vesa_05h
1350}
1351
1352static void
1353handle_104f06(struct bregs *regs)
1354{
1355 // XXX - vbe_biosfn_set_get_logical_scan_line_length
1356 // XXX - OR cirrus_vesa_06h
1357}
1358
1359static void
1360handle_104f07(struct bregs *regs)
1361{
1362 // XXX - vbe_biosfn_set_get_display_start
1363 // XXX - OR cirrus_vesa_07h
1364}
1365
1366static void
1367handle_104f08(struct bregs *regs)
1368{
1369 // XXX - vbe_biosfn_set_get_dac_palette_format
1370}
1371
1372static void
1373handle_104f0a(struct bregs *regs)
1374{
1375 // XXX - vbe_biosfn_return_protected_mode_interface
1376}
1377
1378static void
1379handle_104fXX(struct bregs *regs)
1380{
1381 debug_stub(regs);
1382 regs->ax = 0x0100;
1383}
1384
1385static void
1386handle_104f(struct bregs *regs)
1387{
Kevin O'Connor99e08b72009-05-17 00:07:31 -04001388 if (! CONFIG_VBE || !vbe_has_vbe_display()) {
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001389 handle_104fXX(regs);
1390 return;
1391 }
1392
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001393 switch (regs->al) {
1394 case 0x00: handle_104f00(regs); break;
1395 case 0x01: handle_104f01(regs); break;
1396 case 0x02: handle_104f02(regs); break;
1397 case 0x03: handle_104f03(regs); break;
1398 case 0x04: handle_104f04(regs); break;
1399 case 0x05: handle_104f05(regs); break;
1400 case 0x06: handle_104f06(regs); break;
1401 case 0x07: handle_104f07(regs); break;
1402 case 0x08: handle_104f08(regs); break;
1403 case 0x0a: handle_104f0a(regs); break;
1404 default: handle_104fXX(regs); break;
1405 }
1406}
1407
1408
1409static void
1410handle_10XX(struct bregs *regs)
1411{
1412 debug_stub(regs);
1413}
1414
1415// INT 10h Video Support Service Entry Point
1416void VISIBLE16
1417handle_10(struct bregs *regs)
1418{
1419 debug_enter(regs, DEBUG_VGA_10);
1420 switch (regs->ah) {
1421 case 0x00: handle_1000(regs); break;
1422 case 0x01: handle_1001(regs); break;
1423 case 0x02: handle_1002(regs); break;
1424 case 0x03: handle_1003(regs); break;
1425 case 0x04: handle_1004(regs); break;
1426 case 0x05: handle_1005(regs); break;
1427 case 0x06: handle_1006(regs); break;
1428 case 0x07: handle_1007(regs); break;
1429 case 0x08: handle_1008(regs); break;
1430 case 0x09: handle_1009(regs); break;
1431 case 0x0a: handle_100a(regs); break;
1432 case 0x0b: handle_100b(regs); break;
1433 case 0x0c: handle_100c(regs); break;
1434 case 0x0d: handle_100d(regs); break;
1435 case 0x0e: handle_100e(regs); break;
1436 case 0x0f: handle_100f(regs); break;
1437 case 0x10: handle_1010(regs); break;
1438 case 0x11: handle_1011(regs); break;
1439 case 0x12: handle_1012(regs); break;
1440 case 0x13: handle_1013(regs); break;
1441 case 0x1a: handle_101a(regs); break;
1442 case 0x1b: handle_101b(regs); break;
1443 case 0x1c: handle_101c(regs); break;
1444 case 0x4f: handle_104f(regs); break;
1445 default: handle_10XX(regs); break;
1446 }
1447}
1448
1449
1450/****************************************************************
1451 * VGA post
1452 ****************************************************************/
1453
1454static void
1455init_bios_area()
1456{
1457 // init detected hardware BIOS Area
1458 // set 80x25 color (not clear from RBIL but usual)
1459 u16 eqf = GET_BDA(equipment_list_flags);
1460 SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1461
1462 // Just for the first int10 find its children
1463
1464 // the default char height
1465 SET_BDA(char_height, 0x10);
1466
1467 // Clear the screen
1468 SET_BDA(video_ctl, 0x60);
1469
1470 // Set the basic screen we have
1471 SET_BDA(video_switches, 0xf9);
1472
1473 // Set the basic modeset options
1474 SET_BDA(modeset_ctl, 0x51);
1475
1476 // Set the default MSR
1477 SET_BDA(video_msr, 0x09);
1478}
1479
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001480void VISIBLE16
1481vga_post(struct bregs *regs)
1482{
1483 debug_enter(regs, DEBUG_VGA_POST);
1484
Kevin O'Connor8bc059e2009-05-17 21:19:36 -04001485 vgahw_init();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001486
1487 init_bios_area();
1488
Kevin O'Connor21079f42009-05-16 21:30:10 -04001489 if (CONFIG_VBE)
1490 vbe_init();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001491
1492 extern void entry_10(void);
Kevin O'Connord113a992009-05-16 21:05:02 -04001493 SET_IVT(0x10, get_global_seg(), (u32)entry_10);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001494
1495 if (CONFIG_CIRRUS)
1496 cirrus_init();
1497
1498 // XXX - clear screen and display info
1499
1500 // XXX: fill it
1501 SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
Kevin O'Connord113a992009-05-16 21:05:02 -04001502 SET_VGA(video_save_pointer_table[1], get_global_seg());
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001503
1504 // Fixup checksum
1505 extern u8 _rom_header_size, _rom_header_checksum;
1506 SET_VGA(_rom_header_checksum, 0);
Kevin O'Connord113a992009-05-16 21:05:02 -04001507 u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001508 SET_VGA(_rom_header_checksum, sum);
1509}