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