VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/BIOS/vgabios.c@ 94451

Last change on this file since 94451 was 94451, checked in by vboxsync, 2 years ago

VGABIOS: When restoring state, we have to first set the CRTC base and only then access the CRTC registers, duh!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.1 KB
Line 
1// ============================================================================================
2/*
3 * vgabios.c
4 */
5// ============================================================================================
6//
7// Copyright (C) 2001,2002 the LGPL VGABios developers Team
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22//
23// ============================================================================================
24//
25// This VGA Bios is specific to the plex86/bochs Emulated VGA card.
26// You can NOT drive any physical vga card with it.
27//
28// ============================================================================================
29//
30// This file contains code ripped from :
31// - rombios.c of plex86
32//
33// This VGA Bios contains fonts from :
34// - fntcol16.zip (c) by Joseph Gil avalable at :
35// ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
36// These fonts are public domain
37//
38// This VGA Bios is based on information taken from :
39// - Kevin Lawton's vga card emulation for bochs/plex86
40// - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
41// - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
42// - Michael Abrash's Graphics Programming Black Book
43// - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
44// - DOSEMU 1.0.1 source code for several tables values and formulas
45//
46// Thanks for patches, comments and ideas to :
47// - techt@pikeonline.net
48//
49// ============================================================================================
50
51
52/*
53 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
54 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
55 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
56 * a choice of LGPL license versions is made available with the language indicating
57 * that LGPLv2 or any later version may be used, or where a choice of which version
58 * of the LGPL is applied is otherwise unspecified.
59 */
60
61#include <inttypes.h>
62#include "vgabios.h"
63
64#ifdef VBE
65#include "vbe.h"
66#endif
67
68#include "inlines.h"
69
70/* Declares */
71extern void vgabios_int10_handler(void);
72#pragma aux vgabios_int10_handler "*";
73
74// Output
75void __cdecl unimplemented(void);
76void __cdecl unknown(void);
77
78static uint8_t find_vga_entry();
79static void biosfn_load_text_8_16_pat(uint8_t AL, uint8_t BL);
80
81extern uint8_t readx_byte(uint16_t seg, uint16_t offset);
82
83#ifdef VBE
84extern uint16_t __cdecl vbe_has_vbe_display(void);
85extern void vbe_init(void);
86#endif
87
88void set_int_vector(uint8_t int_vec, void __far *ptr)
89{
90 void __far * __far *ivt = 0;
91
92 ivt[int_vec] = ptr;
93}
94
95//@todo!!
96#if 0
97
98vgabios_name:
99#ifdef VBOX
100.ascii "VirtualBox VGA BIOS"
101#else
102.ascii "Plex86/Bochs VGABios"
103#endif
104.ascii " "
105.byte 0x00
106
107#ifndef VBOX
108vgabios_version:
109#ifndef VGABIOS_VERS
110.ascii "current-cvs"
111#else
112.ascii VGABIOS_VERS
113#endif
114.ascii " "
115
116vgabios_date:
117.ascii VGABIOS_DATE
118.byte 0x0a,0x0d
119.byte 0x00
120#endif
121
122#ifndef VBOX
123char vgabios_copyright[] = "(C) 2003 the LGPL VGABios developers Team\r\n";
124char vgabios_license[] = "This VGA/VBE Bios is released under the GNU LGPL\r\n\r\n";
125char vgabios_website[] = "Please visit :\r\n" \
126 " . http://www.plex86.org\r\n" \
127 " . http://bochs.sourceforge.net\r\n" \
128 " . http://www.nongnu.org/vgabios\r\n\r\n"
129#endif
130
131#endif
132
133extern void set_mode(int mode);
134#pragma aux set_mode = \
135 "xor ah, ah" \
136 "int 10h" \
137 parm [ax];
138
139char msg_vga_init[] = "Oracle VM VirtualBox Version " VBOX_VERSION_STRING " VGA BIOS\r\n";
140
141/*
142 * Boot time harware inits
143 */
144void init_vga_card(void)
145{
146 /* Switch to color mode and enable CPU access 480 lines. */
147 outb(0x3C2, 0xC3);
148 /* More than 64k 3C4/04. */
149 /// @todo 16-bit write
150 outb(0x3C4, 0x04);
151 outb(0x3C5, 0x02);
152
153#ifdef DEBUG_VGA
154 printf(msg_vga_init);
155#endif
156}
157
158#include "vgatables.h"
159#include "vgadefs.h"
160
161// --------------------------------------------------------------------------------------------
162
163#pragma pack(0)
164
165/* Alphanumeric character set override. */
166typedef struct {
167 uint8_t c_height; /* Bytes/lines per character. */
168 uint8_t cgen_bank; /* Character generator bank. */
169 uint16_t char_num; /* Number of chars defined. */
170 uint16_t char_1st; /* First char code in table. */
171 uint16_t font_ofs; /* Font definition table offset. */
172 uint16_t font_seg; /* Font definition table segment. */
173 uint8_t n_rows; /* Number of text rows shown. */
174 uint8_t modes[1]; /* Applicable modes list, 0xFF terminated. */
175} cso_txt;
176
177/* Graphics character set override. */
178typedef struct {
179 uint8_t c_height; /* Lines per character. */
180 uint16_t c_len; /* Bytes per character. */
181 uint16_t font_ofs; /* Font definition table offset. */
182 uint16_t font_seg; /* Font definition table segment. */
183 uint8_t modes[1]; /* Applicable modes list, 0xFF terminated. */
184} cso_grf;
185
186struct dcc {
187 uint8_t n_ent;
188 uint8_t version;
189 uint8_t max_code;
190 uint8_t reserved;
191 uint16_t dccs[16];
192} dcc_table = {
193 16,
194 1,
195 7,
196 0
197};
198
199struct ssa {
200 uint16_t size;
201 void __far *dcc;
202 void __far *sacs;
203 void __far *pal;
204 void __far *resvd[3];
205
206} secondary_save_area = {
207 sizeof(struct ssa),
208 &dcc_table
209};
210
211void __far *video_save_pointer_table[7] = {
212 &video_param_table,
213 0,
214 0,
215 0,
216 &secondary_save_area
217};
218
219/*
220 * Boot time bios area inits
221 */
222void init_bios_area(void)
223{
224 uint8_t __far *bda;
225
226 bda = 0x40 :> 0;
227
228 /* Indicate 80x25 color was detected. */
229 bda[BIOSMEM_INITIAL_MODE] = (bda[BIOSMEM_INITIAL_MODE] & 0xcf) | 0x20;
230 /* Just for the first int10 find its children. */
231
232 /* The default char height. */
233 bda[BIOSMEM_CHAR_HEIGHT] = 16;
234 /* Clear the screen. */
235 bda[BIOSMEM_VIDEO_CTL] = 0x60;
236 /* Set the basic screen we have. */
237 bda[BIOSMEM_SWITCHES] = 0xf9;
238 /* Set the basic mode set options. */
239 bda[BIOSMEM_MODESET_CTL] = 0x51;
240 /* Set the default MSR. */
241 bda[BIOSMEM_CURRENT_MSR] = 0x09;
242 /* Initialize the default save area pointer. */
243 *(void __far * __far *)&bda[BIOSMEM_VS_POINTER] = video_save_pointer_table;
244}
245
246// ============================================================================================
247//
248// Init Entry point
249//
250// ============================================================================================
251void __far __cdecl vgabios_init_func(void)
252{
253 init_vga_card();
254 init_bios_area();
255#ifdef VBE
256 vbe_init();
257#endif
258 set_int_vector(0x10, vgabios_int10_handler);
259 set_int_vector(0x6D, vgabios_int10_handler);
260#ifdef CIRRUS
261 cirrus_init();
262#endif
263
264#ifndef VBOX
265 display_splash_screen();
266
267 // init video mode and clear the screen
268 // @@AS: Do not remove this init, because it will break VESA graphics
269 set_mode(3);
270
271 display_info();
272
273#ifdef VBE
274 vbe_display_info();
275#endif
276
277#ifdef CIRRUS
278 cirrus_display_info();
279#endif
280
281#else /* VBOX */
282
283//#ifdef DEBUG_bird
284 /* Init video mode and clear the screen */
285 set_mode(3);
286//#endif
287#endif /* VBOX */
288}
289
290#include "vgafonts.h"
291
292#ifndef VBOX
293// --------------------------------------------------------------------------------------------
294/*
295 * Boot time Splash screen
296 */
297static void display_splash_screen()
298{
299}
300
301// --------------------------------------------------------------------------------------------
302/*
303 * Tell who we are
304 */
305
306static void display_string(void)
307{
308 // Get length of string
309ASM_START
310 mov ax,ds
311 mov es,ax
312 mov di,si
313 xor cx,cx
314 not cx
315 xor al,al
316 cld
317 repne
318 scasb
319 not cx
320 dec cx
321 push cx
322
323 mov ax,#0x0300
324 mov bx,#0x0000
325 int #0x10
326
327 pop cx
328 mov ax,#0x1301
329 mov bx,#0x000b
330 mov bp,si
331 int #0x10
332ASM_END
333}
334
335static void display_info(void)
336{
337 display_string(vgabios_name);
338 display_string(vgabios_version);
339 display_string(vgabios_copyright);
340 display_string(vgabios_license);
341 display_string(vgabios_website);
342}
343
344#endif
345
346// --------------------------------------------------------------------------------------------
347#ifdef VGA_DEBUG
348void __cdecl int10_debugmsg(uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP, uint16_t BX,
349 uint16_t DX, uint16_t CX, uint16_t AX, uint16_t DS, uint16_t ES, uint16_t FLAGS)
350{
351 /* Function 0Eh is write char and would generate way too much output. */
352 if (GET_AH() != 0x0E)
353 printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n", GET_AH(), GET_AL(), BX, CX, DX);
354}
355#endif
356
357static void vga_get_cursor_pos(uint8_t page, uint16_t STACK_BASED *scans, uint16_t STACK_BASED *loc)
358{
359 if (page > 7) {
360 *scans = 0;
361 *loc = 0;
362 } else {
363 // FIXME should handle VGA 14/16 lines
364 *scans = read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE);
365 *loc = read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS + page * 2);
366 }
367}
368
369/* Look for a glyph bitmap in a given font. */
370static uint16_t vga_find_glyph(uint8_t __far *font, uint8_t STACK_BASED *glyph, uint8_t cp, uint16_t n_glyphs, uint8_t cheight)
371{
372 uint16_t codepoint = 0; /* Zero returned when glyph not found. */
373
374 while (n_glyphs--) {
375 if (!repe_cmpsb(font, glyph, cheight)) {
376 codepoint = cp | 0x8000; /* Found matching glyph! */
377 break;
378 }
379 font += cheight;
380 ++cp; /* Increment code point number. */
381 }
382 return codepoint;
383}
384
385static void vga_read_glyph_planar(uint8_t __far *vptr, uint16_t stride, uint8_t STACK_BASED *glyph, uint8_t cheight)
386{
387 /* Set Mode Register (GR5) to Read Mode 1. Assuming default register
388 * state from our mode set, this does all the hard work for us such that
389 * reading a byte from video memory gives us a bit mask for all eight
390 * pixels, for both 16-color and monochrome modes.
391 */
392 outw(VGAREG_GRDC_ADDRESS, 0x0805);
393
394 while (cheight--) {
395 *glyph++ = ~*vptr;
396 vptr += stride;
397 }
398
399 /* Put GR5 back to Read Mode 0. */
400 outw(VGAREG_GRDC_ADDRESS, 0x0005);
401}
402
403static uint16_t vga_char_ofs_planar(uint8_t xcurs, uint8_t ycurs, uint16_t nbcols, uint8_t page, uint8_t cheight)
404{
405 uint16_t ofs;
406
407 ofs = ycurs * nbcols * cheight + xcurs;
408 ofs += page * read_word(BIOSMEM_SEG, BIOSMEM_PAGE_SIZE);
409
410 return ofs;
411}
412
413static uint8_t vga_read_char_planar(uint16_t nbcols, uint16_t ofs, uint8_t cheight)
414{
415 uint8_t glyph[16]; /* NB: Don't try taller characters! */
416
417 vga_read_glyph_planar(0xA000 :> (uint8_t *)ofs, nbcols, &glyph, cheight);
418
419 /* Look through font pointed to by INT 43h. */
420 return vga_find_glyph((void __far *)read_dword(0, 0x43 * 4), &glyph, 0, 256, cheight);
421}
422
423static uint16_t vga_char_ofs_linear(uint8_t xcurs, uint8_t ycurs, uint16_t nbcols, uint8_t page, uint8_t cheight)
424{
425 uint16_t ofs;
426
427 ofs = ycurs * nbcols * cheight + xcurs;
428 ofs *= 8;
429 return ofs;
430}
431
432static void vga_read_glyph_linear(uint8_t __far *vptr, uint16_t stride, uint8_t STACK_BASED *glyph, uint8_t cheight)
433{
434 uint8_t bmap, cbit;
435 int i;
436
437 /* Zero pixels are background, everything else foreground. */
438 while (cheight--) {
439 bmap = 0;
440 cbit = 0x80;
441 for (i = 0; i < 8; ++i) {
442 if (vptr[i])
443 bmap |= cbit;
444 cbit >>= 1;
445 }
446 *glyph++ = bmap;
447 vptr += stride;
448 }
449}
450
451static uint8_t vga_read_char_linear(uint16_t nbcols, uint16_t ofs, uint8_t cheight)
452{
453 uint8_t glyph[16]; /* NB: Don't try taller characters! */
454
455 vga_read_glyph_linear(0xA000 :> (uint8_t *)ofs, nbcols * 8, &glyph, cheight);
456
457 /* Look through font pointed to by INT 43h. */
458 return vga_find_glyph((void __far *)read_dword(0, 0x43 * 4), &glyph, 0, 256, cheight);
459}
460
461static uint8_t vga_read_2bpp_char(uint8_t __far *vptr)
462{
463 uint16_t mask, pixb;
464 uint8_t bmap, cbit;
465 int i;
466
467 mask = 0xC000; /* Check two bits at a time to see if they're zero. */
468 cbit = 0x80; /* Go from left to right. */
469 bmap = 0;
470 pixb = swap_16(*((uint16_t __far *)vptr));
471 /* Go through 8 lines/words. */
472 for (i = 0; i < 8; ++i) {
473 if (pixb & mask)
474 bmap |= cbit;
475 cbit >>= 1;
476 mask >>= 2;
477 }
478 return bmap;
479}
480
481static void vga_read_glyph_cga(uint16_t ofs, uint8_t STACK_BASED *glyph, uint8_t mode)
482{
483 int i;
484 uint8_t __far *vptr;
485
486 /* The font size is fixed at 8x8. Stride is always 80 bytes because the
487 * mode is either 80 characters wide at 1bpp or 40 characters at 2bpp.
488 */
489 if (mode != 6) {
490 /* Adjust offset for 2bpp. */
491 vptr = 0xB800 :> (uint8_t *)(ofs * 2);
492 /* For 2bpp modes, we have to extract the bits by hand. */
493 for (i = 0; i < 4; ++i) {
494 *glyph++ = vga_read_2bpp_char(vptr);
495 *glyph++ = vga_read_2bpp_char(vptr + 0x2000);
496 vptr += 80;
497 }
498 } else {
499 vptr = 0xB800 :> (uint8_t *)ofs;
500 for (i = 0; i < 4; ++i) {
501 *glyph++ = vptr[0];
502 *glyph++ = vptr[0x2000];
503 vptr += 80;
504 }
505 }
506}
507
508static uint16_t vga_char_ofs_cga(uint8_t xcurs, uint8_t ycurs, uint16_t nbcols)
509{
510 /* Multiply ony by 8 due to line interleaving. NB: Caller
511 * has to multiply the result for two for 2bpp mode.
512 */
513 return ycurs * nbcols * 4 + xcurs;
514}
515
516static uint8_t vga_read_char_cga(uint16_t ofs, uint8_t mode)
517{
518 uint8_t glyph[8]; /* Char height is hardcoded to 8. */
519 uint16_t found;
520
521 /* Segment would be B000h for mono modes; we don't do those. */
522 vga_read_glyph_cga(ofs, &glyph, mode);
523
524 /* Look through the first half of the font pointed to by INT 43h. */
525 found = vga_find_glyph((void __far *)read_dword(0, 0x43 * 4), &glyph, 0, 128, 8);
526 /* If not found, look for the second half pointed to by INT 1Fh */
527 if (!(found & 0x8000)) {
528 void __far *int1f;
529
530 int1f = (void __far *)read_dword(0, 0x1f * 4);
531 if (int1f) /* If null pointer, skip. */
532 found = vga_find_glyph(int1f, &glyph, 128, 128, 8);
533 }
534 return found;
535}
536
537static void vga_read_char_attr(uint8_t page, uint16_t STACK_BASED *chr_atr)
538{
539 uint8_t xcurs, ycurs, mode, line, cheight;
540 uint16_t nbcols, nbrows, address;
541 uint16_t cursor, dummy, ofs;
542
543 // Get the mode
544 mode = read_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE);
545 line = find_vga_entry(mode);
546 if (line == 0xFF)
547 return;
548
549 // Get the cursor pos for the page
550 vga_get_cursor_pos(page, &dummy, &cursor);
551 xcurs = cursor & 0x00ff;
552 ycurs = (cursor & 0xff00) >> 8;
553
554 // Get the dimensions
555 nbrows = read_byte(BIOSMEM_SEG, BIOSMEM_NB_ROWS) + 1;
556 nbcols = read_word(BIOSMEM_SEG, BIOSMEM_NB_COLS);
557
558 if (vga_modes[line].class == TEXT) {
559 // Compute the address
560 address = SCREEN_MEM_START(nbcols, nbrows, page) + (xcurs + ycurs * nbcols) * 2;
561 *chr_atr = read_word(vga_modes[line].sstart, address);
562 } else {
563 switch (vga_modes[line].memmodel) {
564 case CGA:
565 /* For CGA graphics, font size is hardcoded at 8x8. */
566 ofs = vga_char_ofs_cga(xcurs, ycurs, nbcols);
567 *chr_atr = vga_read_char_cga(ofs, mode);
568 break;
569 case PLANAR1:
570 case PLANAR4:
571 cheight = read_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
572 ofs = vga_char_ofs_planar(xcurs, ycurs, nbcols, page, cheight);
573 *chr_atr = vga_read_char_planar(nbcols, ofs, cheight);
574 break;
575 case LINEAR8:
576 cheight = read_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
577 ofs = vga_char_ofs_linear(xcurs, ycurs, nbcols, page, cheight);
578 *chr_atr = vga_read_char_linear(nbcols, ofs, cheight);
579 break;
580 default:
581#ifdef VGA_DEBUG
582 unimplemented();
583#endif
584 break;
585 }
586 }
587}
588
589static void vga_get_font_info (uint16_t func, uint16_t STACK_BASED *u_seg, uint16_t STACK_BASED *u_ofs,
590 uint16_t STACK_BASED *c_height, uint16_t STACK_BASED *max_row)
591{
592 void __far *ptr;
593
594 switch (func) {
595 case 0x00:
596 ptr = (void __far *)read_dword(0x00, 0x1f * 4);
597 break;
598 case 0x01:
599 ptr = (void __far *)read_dword(0x00, 0x43 * 4);
600 break;
601 case 0x02:
602 ptr = vgafont14;
603 break;
604 case 0x03:
605 ptr = vgafont8;
606 break;
607 case 0x04:
608 ptr = vgafont8 + 128 * 8;
609 break;
610 case 0x05:
611 ptr = vgafont14alt;
612 break;
613 case 0x06:
614 ptr = vgafont16;
615 break;
616 case 0x07:
617 ptr = vgafont16alt;
618 break;
619 default:
620#ifdef VGA_DEBUG
621 printf("Get font info subfn(%02x) not implemented\n", func);
622#endif
623 return;
624 }
625 /* Split the far pointer and write it back. */
626 *u_ofs = (uint16_t)ptr;
627 *u_seg = (uint32_t)ptr >> 16;
628
629 /* The character height (effectively bytes per glyph). */
630 *c_height = read_byte(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
631
632 /* The highest row number. */
633 *max_row = read_byte(BIOSMEM_SEG, BIOSMEM_NB_ROWS);
634}
635
636static void vga_read_pixel(uint8_t page, uint16_t col, uint16_t row, uint16_t STACK_BASED *pixel)
637{
638 uint8_t mode, line, mask, attr, data, i;
639 uint16_t addr;
640
641 /* Determine current mode characteristics. */
642 mode = read_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE);
643 line = find_vga_entry(mode);
644 if (line == 0xFF)
645 return;
646 if (vga_modes[line].class == TEXT)
647 return;
648
649 /* Read data depending on memory model. */
650 switch (vga_modes[line].memmodel) {
651 case PLANAR4:
652 case PLANAR1:
653 addr = col / 8 + row * read_word(BIOSMEM_SEG, BIOSMEM_NB_COLS);
654 addr += read_word(BIOSMEM_SEG, BIOSMEM_PAGE_SIZE) * page;
655 mask = 0x80 >> (col & 0x07);
656 attr = 0x00;
657 for (i = 0; i < 4; i++) {
658 outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
659 data = read_byte(0xa000,addr) & mask;
660 if (data > 0)
661 attr |= (0x01 << i);
662 }
663 break;
664 case CGA:
665 addr = (col >> (4 - vga_modes[line].pixbits)) + (row >> 1) * 80;
666 if (row & 1)
667 addr += 0x2000;
668 data = read_byte(0xb800, addr);
669 if (vga_modes[line].pixbits == 2)
670 attr = (data >> ((3 - (col & 0x03)) * 2)) & 0x03;
671 else
672 attr = (data >> (7 - (col & 0x07))) & 0x01;
673 break;
674 case LINEAR8:
675 addr = col + row * (read_word(BIOSMEM_SEG, BIOSMEM_NB_COLS) * 8);
676 attr = read_byte(0xa000, addr);
677 break;
678 default:
679#ifdef VGA_DEBUG
680 unimplemented();
681#endif
682 attr = 0;
683 }
684 *(uint8_t STACK_BASED *)pixel = attr;
685}
686
687
688
689// --------------------------------------------------------------------------------------------
690/*static*/ void biosfn_perform_gray_scale_summing(uint16_t start, uint16_t count)
691{uint8_t r,g,b;
692 uint16_t i;
693 uint16_t index;
694
695 inb(VGAREG_ACTL_RESET);
696 outb(VGAREG_ACTL_ADDRESS,0x00);
697
698 for( index = 0; index < count; index++ )
699 {
700 // set read address and switch to read mode
701 outb(VGAREG_DAC_READ_ADDRESS,start);
702 // get 6-bit wide RGB data values
703 r=inb( VGAREG_DAC_DATA );
704 g=inb( VGAREG_DAC_DATA );
705 b=inb( VGAREG_DAC_DATA );
706
707 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
708 i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
709
710 if(i>0x3f)i=0x3f;
711
712 // set write address and switch to write mode
713 outb(VGAREG_DAC_WRITE_ADDRESS,start);
714 // write new intensity value
715 outb( VGAREG_DAC_DATA, i&0xff );
716 outb( VGAREG_DAC_DATA, i&0xff );
717 outb( VGAREG_DAC_DATA, i&0xff );
718 start++;
719 }
720 inb(VGAREG_ACTL_RESET);
721 outb(VGAREG_ACTL_ADDRESS,0x20);
722#ifdef VBOX
723 inb(VGAREG_ACTL_RESET);
724#endif /* VBOX */
725}
726
727// --------------------------------------------------------------------------------------------
728static void biosfn_set_cursor_shape(uint8_t CH, uint8_t CL)
729{
730 uint16_t cheight, curs, crtc_addr;
731 int cga_emu;
732
733 /* Unmodified input is stored in the BDA. */
734 curs = (CH << 8) + CL;
735 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_TYPE, curs);
736
737 /* Check if VGA is active. If not, just write the input to the CRTC. */
738 if (!(read_byte(BIOSMEM_SEG, BIOSMEM_VIDEO_CTL) & 8)) {
739 /* Trying to disable the cursor? */
740 if ((CH & 0x60) == 0x20) {
741 /* Special IBM-compatible value to turn off cursor. */
742 CH = 0x1E;
743 CL = 0;
744 } else {
745 cga_emu = !(read_byte(BIOSMEM_SEG, BIOSMEM_VIDEO_CTL) & 1);
746
747 /* If CGA cursor emulation is on and this is a text mode, adjust.
748 * But if cursor star or end is bigger than 31, don't adjust.
749 */
750 /// @todo Figure out if this is a text mode
751 if (cga_emu /* && text mode*/ && (CH < 32) && (CL < 32)) {
752 cheight = read_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
753
754 /* Is the end lower than start? VGA does not wrap around.*/
755 if (CL < CH) {
756 /* For zero CL (end), leave values unchanged. */
757 if (CL) {
758 CH = 0;
759 CL = cheight - 1;
760 }
761 } else {
762 if (((CL | CH) >= cheight) || ((CL != cheight - 1) && (CH != cheight - 2))) {
763 /* If it's an overbar cursor, don't adjust. */
764 if (CL > 3) {
765 if (CL <= CH + 2) {
766 /* It's it a normal underline style cursor. */
767 CH = CH - CL + cheight - 1;
768 CL = cheight - 1;
769 if (cheight >= 14) {
770 /* Shift up one pixel for normal EGA/VGA fonts. */
771 CL--;
772 CH--;
773 }
774 } else if (CH <= 2) {
775 /* It's a full block cursor. */
776 CL = cheight - 1;
777 } else {
778 /* It's a half block cursor. */
779 CH = cheight / 2;
780 CL = cheight - 1;
781 }
782 }
783 }
784 }
785 }
786 }
787 }
788
789 // CTRC regs 0x0a and 0x0b
790 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
791 outb(crtc_addr, 0x0a);
792 outb(crtc_addr + 1, CH);
793 outb(crtc_addr, 0x0b);
794 outb(crtc_addr + 1 ,CL);
795}
796
797// --------------------------------------------------------------------------------------------
798static void biosfn_set_cursor_pos (uint8_t page, uint16_t cursor)
799{
800 uint8_t xcurs,ycurs,current;
801 uint16_t nbcols,nbrows,address,crtc_addr;
802
803 // Should not happen...
804 if(page>7)return;
805
806 // Bios cursor pos
807 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
808
809 // Set the hardware cursor
810 current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
811 if(page==current)
812 {
813 // Get the dimensions
814 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
815 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
816
817 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
818
819 // Calculate the address knowing nbcols nbrows and page num
820 address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
821
822 // CRTC regs 0x0e and 0x0f
823 crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
824 outb(crtc_addr,0x0e);
825 outb(crtc_addr+1,(address&0xff00)>>8);
826 outb(crtc_addr,0x0f);
827 outb(crtc_addr+1,address&0x00ff);
828 }
829}
830
831// --------------------------------------------------------------------------------------------
832static void biosfn_set_active_page(uint8_t page)
833{
834 uint16_t cursor,dummy,crtc_addr;
835 uint16_t nbcols,nbrows,address;
836 uint8_t mode,line;
837
838 if(page>7)return;
839
840 // Get the mode
841 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
842 line=find_vga_entry(mode);
843 if(line==0xFF)return;
844
845 // Get pos curs pos for the right page
846 vga_get_cursor_pos(page,&dummy,&cursor);
847
848 if(vga_modes[line].class==TEXT)
849 {
850 // Get the dimensions
851 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
852 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
853
854 // Calculate the address knowing nbcols nbrows and page num
855 address=SCREEN_MEM_START(nbcols,nbrows,page);
856 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
857
858 // Start address
859 address=SCREEN_IO_START(nbcols,nbrows,page);
860 }
861 else
862 {
863 address = page * video_param_table[line_to_vpti[line]].slength;
864 }
865
866 // CRTC regs 0x0c and 0x0d
867 crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
868 outb(crtc_addr,0x0c);
869 outb(crtc_addr+1,(address&0xff00)>>8);
870 outb(crtc_addr,0x0d);
871 outb(crtc_addr+1,address&0x00ff);
872
873 // And change the BIOS page
874 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
875
876#ifdef VGA_DEBUG
877 printf("Set active page %02x address %04x\n",page,address);
878#endif
879
880 // Display the cursor, now the page is active
881 biosfn_set_cursor_pos(page,cursor);
882}
883
884/// Recursive BIOS invocation, uses vector 6Dh
885extern void vga_font_set(uint8_t function, uint8_t data);
886#pragma aux vga_font_set = \
887 "mov ah, 11h" \
888 "int 6Dh" \
889 parm [al] [bl];
890
891// ============================================================================================
892//
893// BIOS functions
894//
895// ============================================================================================
896
897/* CGA-compatible MSR (0x3D8) register values for first modes 0-7. */
898uint8_t cga_msr[8] = {
899 0x2C, 0x28, 0x2D, 0x29, 0x2A, 0x2E, 0x1E, 0x29
900};
901
902/* Convert index in vga_modes[] to index in video_param_table[] for 200-line (CGA) text modes. */
903static int8_t line_to_vpti_200[8] = {
904 0x00, 0x01, 0x02, 0x03, -1, -1, -1, 0x07
905};
906
907/* Same for 350-line (EGA) text modes. */
908static int8_t line_to_vpti_350[8] = {
909 0x13, 0x14, 0x15, 0x16, -1, -1, -1, 0x07
910};
911
912/* Same for 400-line (VGA) text modes. */
913static int8_t line_to_vpti_400[8] = {
914 0x17, 0x17, 0x18, 0x18, -1, -1, -1, 0x19
915};
916
917int find_vpti(uint8_t line)
918{
919 int idx;
920 uint8_t mctl;
921
922 if (vga_modes[line].class == TEXT) {
923 mctl = read_byte(BIOSMEM_SEG, BIOSMEM_MODESET_CTL);
924 if (mctl & 0x10)
925 idx = line_to_vpti_400[line];
926 else if (mctl & 0x80)
927 idx = line_to_vpti_200[line];
928 else
929 idx = line_to_vpti_350[line];
930 } else
931 idx = line_to_vpti[line];
932
933 return idx;
934}
935
936static void biosfn_load_text_user_pat(uint8_t AL, uint16_t ES, uint16_t BP, uint16_t CX, uint16_t DX, uint8_t BL, uint8_t BH);
937
938void biosfn_set_video_mode(uint8_t mode)
939{// mode: Bit 7 is 1 if no clear screen
940
941 // Should we clear the screen ?
942 uint8_t noclearmem=mode&0x80;
943 uint8_t line,mmask,vpti;
944 uint8_t modeset_ctl;
945 uint8_t *palette;
946 uint16_t i;
947 uint16_t crtc_addr;
948 void __far * __far *save_area;
949 VideoParamTableEntry __far *vpt;
950
951#ifdef VBE
952 if (vbe_has_vbe_display()) {
953 // Force controller into VGA mode
954 outb(VGAREG_SEQU_ADDRESS,7);
955 outb(VGAREG_SEQU_DATA,0x00);
956 }
957#endif // def VBE
958
959 // The real mode
960 mode=mode&0x7f;
961
962 // Display switching is not supported; mono monitors aren't really either,
963 // but requests to set mode 7 are honored.
964
965 // find the entry in the video modes
966 line=find_vga_entry(mode);
967
968#ifdef VGA_DEBUG
969 printf("mode search %02x found line %02x\n",mode,line);
970#endif
971
972 if(line==0xFF)
973 return;
974
975 // Read the save area pointer.
976 save_area = (void __far *)read_dword(BIOSMEM_SEG, BIOSMEM_VS_POINTER);
977
978 vpti = find_vpti(line);
979 vpt = save_area[0];
980 vpt += vpti;
981
982#if 0 // These are unused, but perhaps they shouldn't be?
983 // Read the bios vga control
984 video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
985
986 // Read the bios vga switches
987 vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
988#endif
989
990 // Read the bios mode set control
991 modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
992
993 // Then we know the number of lines
994// FIXME
995
996 // if palette loading (bit 3 of modeset ctl = 0)
997 if((modeset_ctl&0x08)==0)
998 {// Set the PEL mask
999 outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
1000
1001 // Set the whole dac always, from 0
1002 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
1003
1004 // From which palette
1005 switch(vga_modes[line].dacmodel)
1006 {case 0:
1007 palette=&palette0[0];
1008 break;
1009 case 1:
1010 palette=&palette1[0];
1011 break;
1012 case 2:
1013 palette=&palette2[0];
1014 break;
1015 case 3:
1016 palette=&palette3[0];
1017 break;
1018 }
1019 // Override for CGA text modes.
1020 if(vga_modes[line].class==TEXT)
1021 {
1022 if(vpt->cheight == 8) // CGA
1023 palette=&palette1[0];
1024 }
1025 // Always 256*3 values
1026 for(i=0;i<0x0100;i++)
1027 {if(i<=dac_regs[vga_modes[line].dacmodel])
1028 {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
1029 outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
1030 outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
1031 }
1032 else
1033 {outb(VGAREG_DAC_DATA,0);
1034 outb(VGAREG_DAC_DATA,0);
1035 outb(VGAREG_DAC_DATA,0);
1036 }
1037 }
1038 if((modeset_ctl&0x02)==0x02)
1039 {
1040 biosfn_perform_gray_scale_summing(0x00, 0x100);
1041 }
1042 }
1043
1044 // Reset Attribute Ctl flip-flop
1045 inb(VGAREG_ACTL_RESET);
1046
1047 // Set Attribute Ctl
1048 for(i=0;i<=0x13;i++)
1049 {outb(VGAREG_ACTL_ADDRESS,i);
1050 outb(VGAREG_ACTL_WRITE_DATA,vpt->actl_regs[i]);
1051 }
1052 outb(VGAREG_ACTL_ADDRESS,0x14);
1053 outb(VGAREG_ACTL_WRITE_DATA,0x00);
1054
1055 // Save palette into the save area if it exists.
1056 if(save_area[1])
1057 {
1058 uint8_t __far *dyn_save;
1059
1060 dyn_save = save_area[1];
1061 for (i = 0; i < 16; ++i)
1062 dyn_save[i] = vpt->actl_regs[i];
1063 dyn_save[16] = vpt->actl_regs[17];
1064 }
1065
1066 // Set Sequencer Ctl
1067 outb(VGAREG_SEQU_ADDRESS,0);
1068 outb(VGAREG_SEQU_DATA,0x03);
1069 for(i=1;i<=4;i++)
1070 {outb(VGAREG_SEQU_ADDRESS,i);
1071 outb(VGAREG_SEQU_DATA,vpt->sequ_regs[i - 1]);
1072 }
1073
1074 // Set Grafx Ctl
1075 for(i=0;i<=8;i++)
1076 {outb(VGAREG_GRDC_ADDRESS,i);
1077 outb(VGAREG_GRDC_DATA,vpt->grdc_regs[i]);
1078 }
1079
1080 // Set CRTC address VGA or MDA
1081 crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
1082
1083 // Set the misc register; may change CRTC base!
1084 outb(VGAREG_WRITE_MISC_OUTPUT,vpt->miscreg);
1085
1086 // Disable CRTC write protection
1087 outw(crtc_addr,0x0011);
1088 // Set CRTC regs
1089 for(i=0;i<=0x18;i++)
1090 {outb(crtc_addr,i);
1091 outb(crtc_addr+1,vpt->crtc_regs[i]);
1092 }
1093
1094 // Enable video
1095 outb(VGAREG_ACTL_ADDRESS,0x20);
1096 inb(crtc_addr + VGAREG_ACTL_RESET - VGAREG_VGA_CRTC_ADDRESS);
1097
1098 if(noclearmem==0x00)
1099 {
1100 if(vga_modes[line].class==TEXT)
1101 {
1102 memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
1103 }
1104 else
1105 {
1106 if(mode<0x0d)
1107 {
1108 memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
1109 }
1110 else
1111 {
1112 outb( VGAREG_SEQU_ADDRESS, 0x02 );
1113 mmask = inb( VGAREG_SEQU_DATA );
1114 outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
1115 memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
1116 outb( VGAREG_SEQU_DATA, mmask );
1117 }
1118 }
1119 }
1120
1121 // Set the BIOS mem
1122 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
1123 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,vpt->twidth);
1124 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vpt->slength);
1125 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
1126 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,vpt->theightm1);
1127 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,vpt->cheight);
1128 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
1129 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
1130
1131 // FIXME We nearly have the good tables. to be reworked
1132 write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
1133
1134 if (mode <= 7)
1135 {
1136 write_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MSR, cga_msr[mode]); /* Like CGA reg. 0x3D8 */
1137 write_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_PAL, mode == 6 ? 0x3F : 0x30); /* Like CGA reg. 0x3D9*/
1138 }
1139
1140 // Set cursor shape
1141 if(vga_modes[line].class==TEXT)
1142 {
1143 biosfn_set_cursor_shape(0x06,0x07);
1144 }
1145
1146 /// @todo Could be optimized to a memset since only BDA needs updating.
1147 // Set cursor pos for page 0..7
1148 for(i=0;i<8;i++)
1149 biosfn_set_cursor_pos(i,0x0000);
1150
1151 // Set active page 0
1152 biosfn_set_active_page(0x00);
1153
1154 // Write the fonts in memory
1155 if(vga_modes[line].class==TEXT)
1156 {
1157 cso_txt __far *ovr = save_area[2];
1158
1159 switch (vpt->cheight) {
1160 case 8:
1161 biosfn_load_text_user_pat(0, 0xC000, (uint16_t)vgafont8, 256, 0, 0, vpt->cheight);
1162 break;
1163 case 14:
1164 biosfn_load_text_user_pat(0, 0xC000, (uint16_t)vgafont14, 256, 0, 0, vpt->cheight);
1165 break;
1166 default:
1167 biosfn_load_text_user_pat(0, 0xC000, (uint16_t)vgafont16, 256, 0, 0, vpt->cheight);
1168 }
1169 if (ovr)
1170 {
1171#ifdef VGA_DEBUG
1172 printf("Charmap override found, font at %04x:%04x\n", ovr->font_seg, ovr->font_ofs);
1173#endif
1174 i = 0;
1175 // Does the override support current mode?
1176 while (ovr->modes[i] != 0xff)
1177 {
1178 if (ovr->modes[i] == mode)
1179 break;
1180 ++i;
1181 }
1182 // If there is a valid font override, apply it.
1183 if (ovr->modes[i] == mode)
1184 {
1185#ifdef VGA_DEBUG
1186 printf("Loading override, %04x chars, height %02x\n", ovr->char_num, ovr->c_height);
1187#endif
1188 biosfn_load_text_user_pat(0x10, ovr->font_seg, ovr->font_ofs, ovr->char_num,
1189 ovr->char_1st, ovr->cgen_bank, ovr->c_height);
1190 }
1191 }
1192 vga_font_set(0x03, 0); /* Select font page mode 0. */
1193 }
1194
1195 // Set the ints 0x1F and 0x43
1196 set_int_vector(0x1f, vgafont8+128*8);
1197
1198 switch(vpt->cheight)
1199 {case 8:
1200 set_int_vector(0x43, vgafont8);
1201 break;
1202 case 14:
1203 set_int_vector(0x43, vgafont14);
1204 break;
1205 case 16:
1206 set_int_vector(0x43, vgafont16);
1207 break;
1208 }
1209}
1210
1211// --------------------------------------------------------------------------------------------
1212static void vgamem_copy_pl4(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
1213 uint8_t cols, uint8_t nbcols, uint8_t cheight)
1214{
1215 uint16_t src,dest;
1216 uint8_t i;
1217
1218 src=ysrc*cheight*nbcols+xstart;
1219 dest=ydest*cheight*nbcols+xstart;
1220 outw(VGAREG_GRDC_ADDRESS, 0x0105);
1221 for(i=0;i<cheight;i++)
1222 {
1223 memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
1224 }
1225 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1226}
1227
1228// --------------------------------------------------------------------------------------------
1229static void vgamem_fill_pl4(uint8_t xstart, uint8_t ystart, uint8_t cols,
1230 uint8_t nbcols, uint8_t cheight, uint8_t attr)
1231{
1232 uint16_t dest;
1233 uint8_t i;
1234
1235 dest=ystart*cheight*nbcols+xstart;
1236 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1237 for(i=0;i<cheight;i++)
1238 {
1239 memsetb(0xa000,dest+i*nbcols,attr,cols);
1240 }
1241 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1242}
1243
1244// --------------------------------------------------------------------------------------------
1245static void vgamem_copy_cga(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
1246 uint8_t cols, uint8_t nbcols, uint8_t cheight)
1247{
1248 uint16_t src,dest;
1249 uint8_t i;
1250
1251 src=((ysrc*cheight*nbcols)>>1)+xstart;
1252 dest=((ydest*cheight*nbcols)>>1)+xstart;
1253 for(i=0;i<cheight/2;i++)
1254 {
1255 memcpyb(0xb800,dest+i*nbcols,0xb800,src+i*nbcols,cols);
1256 memcpyb(0xb800,0x2000+dest+i*nbcols,0xb800,0x2000+src+i*nbcols,cols);
1257 }
1258}
1259
1260// --------------------------------------------------------------------------------------------
1261static void vgamem_fill_cga(uint8_t xstart, uint8_t ystart, uint8_t cols,
1262 uint8_t nbcols, uint8_t cheight, uint8_t attr)
1263{
1264 uint16_t dest;
1265 uint8_t i;
1266
1267 dest=((ystart*cheight*nbcols)>>1)+xstart;
1268 for(i=0;i<cheight/2;i++)
1269 {
1270 memsetb(0xb800,dest+i*nbcols,attr,cols);
1271 memsetb(0xb800,0x2000+dest+i*nbcols,attr,cols);
1272 }
1273}
1274
1275// --------------------------------------------------------------------------------------------
1276static void vgamem_copy_linear(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
1277 uint16_t cols, uint16_t nbcols, uint8_t cheight)
1278{
1279 uint16_t src,dest;
1280 uint8_t i;
1281
1282 src=((ysrc*cheight*nbcols)+xstart)*8;
1283 dest=((ydest*cheight*nbcols)+xstart)*8;
1284 cols*=8;
1285 nbcols*=8;
1286 for(i=0;i<cheight;i++)
1287 {
1288 memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
1289 }
1290}
1291
1292// --------------------------------------------------------------------------------------------
1293static void vgamem_fill_linear(uint8_t xstart, uint8_t ystart, uint16_t cols,
1294 uint16_t nbcols, uint8_t cheight, uint8_t attr)
1295{
1296 uint16_t dest;
1297 uint8_t i;
1298
1299 dest=((ystart*cheight*nbcols)+xstart)*8;
1300 cols*=8;
1301 nbcols*=8;
1302 for(i=0;i<cheight;i++)
1303 {
1304 memsetb(0xa000,dest+i*nbcols,attr,cols);
1305 }
1306}
1307
1308// --------------------------------------------------------------------------------------------
1309static void biosfn_scroll(uint8_t nblines, uint8_t attr, uint8_t rul, uint8_t cul,
1310 uint8_t rlr, uint8_t clr, uint8_t page, uint8_t dir)
1311{
1312 // page == 0xFF if current
1313
1314 uint8_t mode,line,cheight,bpp,cols;
1315 uint16_t nbcols,nbrows,i;
1316 uint16_t address;
1317
1318 if(rul>rlr)return;
1319 if(cul>clr)return;
1320
1321 // Get the mode
1322 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1323 line=find_vga_entry(mode);
1324 if(line==0xFF)return;
1325
1326 // Get the dimensions
1327 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1328 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1329
1330 // Get the current page
1331 if(page==0xFF)
1332 page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
1333
1334 if(rlr>=nbrows)rlr=nbrows-1;
1335 if(clr>=nbcols)clr=nbcols-1;
1336 if(nblines>nbrows)nblines=0;
1337 cols=clr-cul+1;
1338
1339 if(vga_modes[line].class==TEXT)
1340 {
1341 // Compute the address
1342 address=SCREEN_MEM_START(nbcols,nbrows,page);
1343#ifdef VGA_DEBUG
1344 printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
1345#endif
1346
1347 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1348 {
1349 memsetw(vga_modes[line].sstart,address,(uint16_t)attr*0x100+' ',nbrows*nbcols);
1350 }
1351 else
1352 {// if Scroll up
1353 if(dir==SCROLL_UP)
1354 {for(i=rul;i<=rlr;i++)
1355 {
1356 if((i+nblines>rlr)||(nblines==0))
1357 memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(uint16_t)attr*0x100+' ',cols);
1358 else
1359 memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
1360 }
1361 }
1362 else
1363 {for(i=rlr;i>=rul;i--)
1364 {
1365 if((i<rul+nblines)||(nblines==0))
1366 memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(uint16_t)attr*0x100+' ',cols);
1367 else
1368 memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
1369 if (i>rlr) break;
1370 }
1371 }
1372 }
1373 }
1374 else
1375 {
1376 cheight=video_param_table[line_to_vpti[line]].cheight;
1377 switch(vga_modes[line].memmodel)
1378 {
1379 case PLANAR4:
1380 case PLANAR1:
1381 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1382 {
1383 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1384 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
1385 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1386 }
1387 else
1388 {// if Scroll up
1389 if(dir==SCROLL_UP)
1390 {for(i=rul;i<=rlr;i++)
1391 {
1392 if((i+nblines>rlr)||(nblines==0))
1393 vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
1394 else
1395 vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
1396 }
1397 }
1398 else
1399 {for(i=rlr;i>=rul;i--)
1400 {
1401 if((i<rul+nblines)||(nblines==0))
1402 vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
1403 else
1404 vgamem_copy_pl4(cul,i-nblines,i,cols,nbcols,cheight);
1405 if (i>rlr) break;
1406 }
1407 }
1408 }
1409 break;
1410 case CGA:
1411 bpp=vga_modes[line].pixbits;
1412 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1413 {
1414 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
1415 }
1416 else
1417 {
1418 if(bpp==2)
1419 {
1420 cul<<=1;
1421 cols<<=1;
1422 nbcols<<=1;
1423 }
1424 // if Scroll up
1425 if(dir==SCROLL_UP)
1426 {for(i=rul;i<=rlr;i++)
1427 {
1428 if((i+nblines>rlr)||(nblines==0))
1429 vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
1430 else
1431 vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
1432 }
1433 }
1434 else
1435 {for(i=rlr;i>=rul;i--)
1436 {
1437 if((i<rul+nblines)||(nblines==0))
1438 vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
1439 else
1440 vgamem_copy_cga(cul,i-nblines,i,cols,nbcols,cheight);
1441 if (i>rlr) break;
1442 }
1443 }
1444 }
1445 break;
1446 case LINEAR8:
1447 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1448 {
1449 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*8);
1450 }
1451 else
1452 {
1453 // if Scroll up
1454 if(dir==SCROLL_UP)
1455 {for(i=rul;i<=rlr;i++)
1456 {
1457 if((i+nblines>rlr)||(nblines==0))
1458 vgamem_fill_linear(cul,i,cols,nbcols,cheight,attr);
1459 else
1460 vgamem_copy_linear(cul,i+nblines,i,cols,nbcols,cheight);
1461 }
1462 }
1463 else
1464 {for(i=rlr;i>=rul;i--)
1465 {
1466 if((i<rul+nblines)||(nblines==0))
1467 vgamem_fill_linear(cul,i,cols,nbcols,cheight,attr);
1468 else
1469 vgamem_copy_linear(cul,i-nblines,i,cols,nbcols,cheight);
1470 if (i>rlr) break;
1471 }
1472 }
1473 }
1474 break;
1475#ifdef VGA_DEBUG
1476 default:
1477 printf("Scroll in graphics mode ");
1478 unimplemented();
1479#endif
1480 }
1481 }
1482}
1483
1484// --------------------------------------------------------------------------------------------
1485static void write_gfx_char_pl4(uint8_t car, uint8_t attr, uint8_t xcurs,
1486 uint8_t ycurs, uint8_t nbcols, uint8_t cheight, uint8_t page)
1487{
1488 uint8_t i,j,mask;
1489 uint8_t __far *fdata;
1490 uint16_t addr,dest,src;
1491
1492 fdata = (void __far *)read_dword(0x00, 0x43 * 4);
1493
1494 addr=xcurs+ycurs*cheight*nbcols;
1495 addr+=read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)*page;
1496 src = car * cheight;
1497 outw(VGAREG_SEQU_ADDRESS, 0x0f02);
1498 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1499 if(attr&0x80)
1500 {
1501 outw(VGAREG_GRDC_ADDRESS, 0x1803);
1502 }
1503 else
1504 {
1505 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1506 }
1507 for(i=0;i<cheight;i++)
1508 {
1509 dest=addr+i*nbcols;
1510 for(j=0;j<8;j++)
1511 {
1512 mask=0x80>>j;
1513 outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
1514 readx_byte(0xa000,dest);
1515 if(fdata[src+i]&mask)
1516 {
1517 write_byte(0xa000,dest,attr&0x0f);
1518 }
1519 else
1520 {
1521 write_byte(0xa000,dest,0x00);
1522 }
1523 }
1524 }
1525 outw(VGAREG_GRDC_ADDRESS, 0xff08);
1526 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1527 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1528}
1529
1530// --------------------------------------------------------------------------------------------
1531static void write_gfx_char_cga(uint8_t car, uint8_t attr, uint8_t xcurs,
1532 uint8_t ycurs, uint8_t nbcols, uint8_t bpp)
1533{
1534 uint8_t i,j,mask,data;
1535 uint8_t *fdata;
1536 uint16_t addr,dest,src;
1537
1538 fdata = &vgafont8;
1539 addr=(xcurs*bpp)+ycurs*320;
1540 src = car * 8;
1541 for(i=0;i<8;i++)
1542 {
1543 dest=addr+(i>>1)*80;
1544 if (i & 1) dest += 0x2000;
1545 mask = 0x80;
1546 /* NB: In 1bpp modes, the attribute is ignored, only the XOR flag has meaning. */
1547 if (bpp == 1)
1548 {
1549 if (attr & 0x80)
1550 {
1551 data = read_byte(0xb800,dest);
1552 data ^= fdata[src+i];
1553 }
1554 else
1555 {
1556 data = fdata[src+i];
1557 }
1558 write_byte(0xb800,dest,data);
1559 }
1560 else
1561 {
1562 while (mask > 0)
1563 {
1564 if (attr & 0x80)
1565 {
1566 data = read_byte(0xb800,dest);
1567 }
1568 else
1569 {
1570 data = 0x00;
1571 }
1572 for(j=0;j<4;j++)
1573 {
1574 if (fdata[src+i] & mask)
1575 {
1576 if (attr & 0x80)
1577 {
1578 data ^= (attr & 0x03) << ((3-j)*2);
1579 }
1580 else
1581 {
1582 data |= (attr & 0x03) << ((3-j)*2);
1583 }
1584 }
1585 mask >>= 1;
1586 }
1587 write_byte(0xb800,dest,data);
1588 dest += 1;
1589 }
1590 }
1591 }
1592}
1593
1594// --------------------------------------------------------------------------------------------
1595static void write_gfx_char_lin(uint8_t car, uint8_t attr, uint8_t xcurs,
1596 uint8_t ycurs, uint8_t nbcols)
1597{
1598 uint8_t i,j,mask,data;
1599 uint8_t *fdata;
1600 uint16_t addr,dest,src;
1601
1602 fdata = &vgafont8;
1603 addr=xcurs*8+ycurs*nbcols*64;
1604 src = car * 8;
1605 for(i=0;i<8;i++)
1606 {
1607 dest=addr+i*nbcols*8;
1608 mask = 0x80;
1609 for(j=0;j<8;j++)
1610 {
1611 data = 0x00;
1612 if (fdata[src+i] & mask)
1613 {
1614 data = attr;
1615 }
1616 write_byte(0xa000,dest+j,data);
1617 mask >>= 1;
1618 }
1619 }
1620}
1621
1622// --------------------------------------------------------------------------------------------
1623static void biosfn_write_char_attr(uint8_t car, uint8_t page, uint8_t attr, uint16_t count)
1624{
1625 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1626 uint16_t nbcols,nbrows,address;
1627 uint16_t cursor,dummy;
1628
1629 // Get the mode
1630 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1631 line=find_vga_entry(mode);
1632 if(line==0xFF)return;
1633
1634 // Get the cursor pos for the page
1635 vga_get_cursor_pos(page,&dummy,&cursor);
1636 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1637
1638 // Get the dimensions
1639 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1640 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1641
1642 if(vga_modes[line].class==TEXT)
1643 {
1644 // Compute the address
1645 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1646
1647 dummy=((uint16_t)attr<<8)+car;
1648 memsetw(vga_modes[line].sstart,address,dummy,count);
1649 }
1650 else
1651 {
1652 // FIXME gfx mode not complete
1653 cheight=video_param_table[line_to_vpti[line]].cheight;
1654 bpp=vga_modes[line].pixbits;
1655 while(count-->0)
1656 {
1657 switch(vga_modes[line].memmodel)
1658 {
1659 case PLANAR1:
1660 attr |= 0x01; /* Color is ignored in 1bpp modes, always foreground. */
1661 case PLANAR4:
1662 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight,page);
1663 break;
1664 case CGA:
1665 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1666 break;
1667 case LINEAR8:
1668 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1669 break;
1670#ifdef VGA_DEBUG
1671 default:
1672 unimplemented();
1673#endif
1674 }
1675 xcurs++;
1676 }
1677 }
1678}
1679
1680// --------------------------------------------------------------------------------------------
1681static void biosfn_write_char_only(uint8_t car, uint8_t page, uint8_t attr, uint16_t count)
1682{
1683 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1684 uint16_t nbcols,nbrows,address;
1685 uint16_t cursor,dummy;
1686
1687 // Get the mode
1688 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1689 line=find_vga_entry(mode);
1690 if(line==0xFF)return;
1691
1692 // Get the cursor pos for the page
1693 vga_get_cursor_pos(page,&dummy,&cursor);
1694 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1695
1696 // Get the dimensions
1697 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1698 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1699
1700 if(vga_modes[line].class==TEXT)
1701 {
1702 // Compute the address
1703 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1704
1705 while(count-->0)
1706 {write_byte(vga_modes[line].sstart,address,car);
1707 address+=2;
1708 }
1709 }
1710 else
1711 {
1712 // FIXME gfx mode not complete
1713 cheight=video_param_table[line_to_vpti[line]].cheight;
1714 bpp=vga_modes[line].pixbits;
1715 while(count-->0)
1716 {
1717 switch(vga_modes[line].memmodel)
1718 {
1719 case PLANAR1:
1720 attr |= 0x01; /* Color is ignored in 1bpp modes, always foreground. */
1721 case PLANAR4:
1722 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight,page);
1723 break;
1724 case CGA:
1725 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1726 break;
1727 case LINEAR8:
1728 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1729 break;
1730#ifdef VGA_DEBUG
1731 default:
1732 unimplemented();
1733#endif
1734 }
1735 xcurs++;
1736 }
1737 }
1738}
1739
1740// --------------------------------------------------------------------------------------------
1741static void biosfn_write_pixel(uint8_t BH, uint8_t AL, uint16_t CX, uint16_t DX)
1742{
1743 uint8_t mode,line,mask,attr,data;
1744 uint16_t addr;
1745
1746 // Get the mode
1747 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1748 line=find_vga_entry(mode);
1749 if(line==0xFF)return;
1750 if(vga_modes[line].class==TEXT)return;
1751
1752 switch(vga_modes[line].memmodel)
1753 {
1754 case PLANAR4:
1755 case PLANAR1:
1756 addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1757 addr += read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE) * BH;
1758 mask = 0x80 >> (CX & 0x07);
1759 outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
1760 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1761 data = readx_byte(0xa000,addr);
1762 if (AL & 0x80)
1763 {
1764 outw(VGAREG_GRDC_ADDRESS, 0x1803);
1765 }
1766 write_byte(0xa000,addr,AL);
1767 outw(VGAREG_GRDC_ADDRESS, 0xff08);
1768 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1769 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1770 break;
1771 case CGA:
1772 if(vga_modes[line].pixbits==2)
1773 {
1774 addr=(CX>>2)+(DX>>1)*80;
1775 }
1776 else
1777 {
1778 addr=(CX>>3)+(DX>>1)*80;
1779 }
1780 if (DX & 1) addr += 0x2000;
1781 data = read_byte(0xb800,addr);
1782 if(vga_modes[line].pixbits==2)
1783 {
1784 attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
1785 mask = 0x03 << ((3 - (CX & 0x03)) * 2);
1786 }
1787 else
1788 {
1789 attr = (AL & 0x01) << (7 - (CX & 0x07));
1790 mask = 0x01 << (7 - (CX & 0x07));
1791 }
1792 if (AL & 0x80)
1793 {
1794 data ^= attr;
1795 }
1796 else
1797 {
1798 data &= ~mask;
1799 data |= attr;
1800 }
1801 write_byte(0xb800,addr,data);
1802 break;
1803 case LINEAR8:
1804 addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
1805 write_byte(0xa000,addr,AL);
1806 break;
1807#ifdef VGA_DEBUG
1808 default:
1809 unimplemented();
1810#endif
1811 }
1812}
1813
1814// --------------------------------------------------------------------------------------------
1815static void biosfn_write_teletype(uint8_t car, uint8_t page, uint8_t attr, uint8_t flag)
1816{// flag = WITH_ATTR / NO_ATTR
1817
1818 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1819 uint16_t nbcols,nbrows,address;
1820 uint16_t cursor,dummy;
1821
1822 // special case if page is 0xff, use current page
1823 if(page==0xff)
1824 page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
1825
1826 // Get the mode
1827 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1828 line=find_vga_entry(mode);
1829 if(line==0xFF)return;
1830
1831 // Get the cursor pos for the page
1832 vga_get_cursor_pos(page,&dummy,&cursor);
1833 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1834
1835 // Get the dimensions
1836 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1837 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1838
1839 switch(car)
1840 {
1841 case '\a': // ASCII 0x07, BEL
1842 //FIXME should beep
1843 break;
1844
1845 case '\b': // ASCII 0x08, BS
1846 if(xcurs>0)xcurs--;
1847 break;
1848
1849 case '\n': // ASCII 0x0A, LF
1850 ycurs++;
1851 break;
1852
1853 case '\r': // ASCII 0x0D, CR
1854 xcurs=0;
1855 break;
1856
1857 default:
1858
1859 if(vga_modes[line].class==TEXT)
1860 {
1861 // Compute the address
1862 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1863
1864 // Write the char
1865 write_byte(vga_modes[line].sstart,address,car);
1866
1867 if(flag==WITH_ATTR)
1868 write_byte(vga_modes[line].sstart,address+1,attr);
1869 }
1870 else
1871 {
1872 // FIXME gfx mode not complete
1873 cheight=video_param_table[line_to_vpti[line]].cheight;
1874 bpp=vga_modes[line].pixbits;
1875 switch(vga_modes[line].memmodel)
1876 {
1877 case PLANAR1:
1878 attr |= 0x01; /* Color is ignored in 1bpp modes, always foreground. */
1879 case PLANAR4:
1880 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight,page);
1881 break;
1882 case CGA:
1883 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1884 break;
1885 case LINEAR8:
1886 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1887 break;
1888#ifdef VGA_DEBUG
1889 default:
1890 unimplemented();
1891#endif
1892 }
1893 }
1894 xcurs++;
1895 // Do we need to wrap ?
1896 if(xcurs==nbcols)
1897 {xcurs=0;
1898 ycurs++;
1899 }
1900 }
1901
1902 // Do we need to scroll ?
1903 if(ycurs==nbrows)
1904 {
1905 if(vga_modes[line].class==TEXT)
1906 {
1907 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
1908 attr=read_byte(vga_modes[line].sstart,address+1);
1909 biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1910 }
1911 else
1912 {
1913 biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1914 }
1915 ycurs-=1;
1916 }
1917
1918 // Set the cursor for the page
1919 cursor=ycurs; cursor<<=8; cursor+=xcurs;
1920 biosfn_set_cursor_pos(page,cursor);
1921}
1922
1923// --------------------------------------------------------------------------------------------
1924static void get_font_access(void)
1925{
1926 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1927 outw(VGAREG_SEQU_ADDRESS, 0x0402);
1928 outw(VGAREG_SEQU_ADDRESS, 0x0704);
1929 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1930 outw(VGAREG_GRDC_ADDRESS, 0x0204);
1931 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1932 outw(VGAREG_GRDC_ADDRESS, 0x0406);
1933}
1934
1935static void release_font_access(void)
1936{
1937 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1938 outw(VGAREG_SEQU_ADDRESS, 0x0302);
1939 outw(VGAREG_SEQU_ADDRESS, 0x0304);
1940 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1941 outw(VGAREG_GRDC_ADDRESS, (((0x0a | ((inb(VGAREG_READ_MISC_OUTPUT) & 0x01) << 2)) << 8) | 0x06));
1942 outw(VGAREG_GRDC_ADDRESS, 0x0004);
1943 outw(VGAREG_GRDC_ADDRESS, 0x1005);
1944}
1945
1946static void set_scan_lines(uint8_t lines)
1947{
1948 uint16_t crtc_addr,cols,vde;
1949 uint8_t crtc_r9,ovl,rows;
1950
1951 crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
1952 outb(crtc_addr, 0x09);
1953 crtc_r9 = inb(crtc_addr+1);
1954 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
1955 outb(crtc_addr+1, crtc_r9);
1956 if(lines==8)
1957 {
1958 biosfn_set_cursor_shape(0x06,0x07);
1959 }
1960 else
1961 {
1962 biosfn_set_cursor_shape(lines-4,lines-3);
1963 }
1964 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
1965 outb(crtc_addr, 0x12);
1966 vde = inb(crtc_addr+1);
1967 outb(crtc_addr, 0x07);
1968 ovl = inb(crtc_addr+1);
1969 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
1970 rows = vde / lines;
1971 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
1972 cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1973 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
1974}
1975
1976static void biosfn_set_font_block(uint8_t BL)
1977{
1978 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1979 outw(VGAREG_SEQU_ADDRESS, 0x0003 | (BL << 8));
1980 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1981}
1982
1983static void biosfn_load_text_user_pat(uint8_t AL, uint16_t ES, uint16_t BP, uint16_t CX,
1984 uint16_t DX, uint8_t BL, uint8_t BH)
1985{
1986 uint16_t blockaddr,dest,i,src;
1987
1988 get_font_access();
1989 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1990 for(i=0;i<CX;i++)
1991 {
1992 src = BP + i * BH;
1993 dest = blockaddr + (DX + i) * 32;
1994 memcpyb(0xA000, dest, ES, src, BH);
1995 }
1996 release_font_access();
1997 if(AL>=0x10)
1998 {
1999 set_scan_lines(BH);
2000 }
2001}
2002
2003static void biosfn_load_text_8_14_pat(uint8_t AL, uint8_t BL)
2004{
2005 uint16_t blockaddr,dest,i,src;
2006
2007 get_font_access();
2008 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2009 for(i=0;i<0x100;i++)
2010 {
2011 src = i * 14;
2012 dest = blockaddr + i * 32;
2013 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont14+src, 14);
2014 }
2015 release_font_access();
2016 if(AL>=0x10)
2017 {
2018 set_scan_lines(14);
2019 }
2020}
2021
2022static void biosfn_load_text_8_8_pat(uint8_t AL, uint8_t BL)
2023{
2024 uint16_t blockaddr,dest,i,src;
2025
2026 get_font_access();
2027 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2028 for(i=0;i<0x100;i++)
2029 {
2030 src = i * 8;
2031 dest = blockaddr + i * 32;
2032 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont8+src, 8);
2033 }
2034 release_font_access();
2035 if(AL>=0x10)
2036 {
2037 set_scan_lines(8);
2038 }
2039}
2040
2041// --------------------------------------------------------------------------------------------
2042static void biosfn_load_text_8_16_pat(uint8_t AL, uint8_t BL)
2043{
2044 uint16_t blockaddr,dest,i,src;
2045
2046 get_font_access();
2047 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2048 for(i=0;i<0x100;i++)
2049 {
2050 src = i * 16;
2051 dest = blockaddr + i * 32;
2052 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont16+src, 16);
2053 }
2054 release_font_access();
2055 if(AL>=0x10)
2056 {
2057 set_scan_lines(16);
2058 }
2059}
2060
2061static void biosfn_load_gfx_8_8_chars(uint16_t ES, uint16_t BP)
2062{
2063 set_int_vector(0x1F, ES:>BP);
2064}
2065
2066static void set_gfx_font(void _far *font, uint16_t cheight, uint8_t row_code, uint8_t rows)
2067{
2068 static uint8_t row_tbl[] = { 0, 14, 25, 43 };
2069
2070 set_int_vector(0x43, font);
2071 if (row_code) {
2072 if (row_code > 3)
2073 row_code = 2; /* Default to 25 rows. */
2074 rows = row_tbl[row_code];
2075 }
2076 /* Else 'rows' used as is. */
2077
2078 write_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT, cheight);
2079 write_word(BIOSMEM_SEG, BIOSMEM_NB_ROWS, rows - 1);
2080}
2081
2082static void biosfn_load_gfx_user_chars(uint16_t ES, uint16_t BP, uint16_t CX,
2083 uint8_t BL, uint8_t DL)
2084{
2085 set_gfx_font(ES:>BP, CX, BL, DL);
2086}
2087
2088/* Some references (RBIL) suggest that only BL is used; that is wrong,
2089 * all of these subfunctions will use DL if BL is zero.
2090 */
2091static void biosfn_load_gfx_8_14_chars(uint8_t BL, uint8_t DL)
2092{
2093 set_gfx_font(vgafont14, 14, BL, DL);
2094}
2095static void biosfn_load_gfx_8_8_dd_chars(uint8_t BL, uint8_t DL)
2096{
2097 set_gfx_font(vgafont8, 8, BL, DL);
2098}
2099static void biosfn_load_gfx_8_16_chars(uint8_t BL, uint8_t DL)
2100{
2101 set_gfx_font(vgafont16, 16, BL, DL);
2102}
2103// --------------------------------------------------------------------------------------------
2104static void biosfn_alternate_prtsc(void)
2105{
2106#ifdef VGA_DEBUG
2107 unimplemented();
2108#endif
2109}
2110// --------------------------------------------------------------------------------------------
2111static void biosfn_set_txt_lines(uint8_t AL)
2112{
2113 uint8_t mctl;
2114
2115 /* Read byte at 40:89. */
2116 mctl = read_byte(BIOSMEM_SEG, BIOSMEM_MODESET_CTL);
2117 mctl = mctl & 0x6F; /* Clear 400/200 line flags. */
2118
2119 switch (AL) /* AL was already validated to be in 0-2 range. */
2120 {
2121 case 0: /* 200 lines. */
2122 mctl |= 0x80;
2123 break;
2124 case 2: /* 400 lines. */
2125 mctl |= 0x10;
2126 break;
2127 }
2128 write_byte(BIOSMEM_SEG, BIOSMEM_MODESET_CTL, mctl);
2129}
2130
2131// --------------------------------------------------------------------------------------------
2132static void biosfn_switch_video_interface (AL,ES,DX) uint8_t AL;uint16_t ES;uint16_t DX;
2133{
2134#ifdef VGA_DEBUG
2135 unimplemented();
2136#endif
2137}
2138static void biosfn_enable_video_refresh_control(uint8_t AL)
2139{
2140#ifdef VGA_DEBUG
2141 unimplemented();
2142#endif
2143}
2144
2145// --------------------------------------------------------------------------------------------
2146static void biosfn_write_string(uint8_t flag, uint8_t page, uint8_t attr, uint16_t count,
2147 uint8_t row, uint8_t col, uint16_t seg, uint16_t offset)
2148{
2149 uint16_t newcurs,oldcurs,dummy;
2150 uint8_t car;
2151
2152 // Read curs info for the page
2153 vga_get_cursor_pos(page,&dummy,&oldcurs);
2154
2155 // if row=0xff special case : use current cursor position
2156 if(row==0xff)
2157 {col=oldcurs&0x00ff;
2158 row=(oldcurs&0xff00)>>8;
2159 }
2160
2161 newcurs=row; newcurs<<=8; newcurs+=col;
2162 biosfn_set_cursor_pos(page,newcurs);
2163
2164 while(count--!=0)
2165 {
2166 car=read_byte(seg,offset++);
2167 if((flag&0x02)!=0)
2168 attr=read_byte(seg,offset++);
2169
2170 biosfn_write_teletype(car,page,attr,WITH_ATTR);
2171 }
2172
2173 // Set back curs pos
2174 if((flag&0x01)==0)
2175 biosfn_set_cursor_pos(page,oldcurs);
2176}
2177
2178// --------------------------------------------------------------------------------------------
2179static void biosfn_read_state_info(uint16_t BX, uint16_t ES, uint16_t DI)
2180{
2181 uint16_t pg_sz;
2182 uint16_t scans;
2183 uint8_t mode;
2184 uint8_t mctl;
2185 uint8_t temp;
2186
2187 mode = read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
2188 pg_sz = read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE);
2189 // Address of static functionality table
2190 write_dword(ES,DI+0x00, (uint32_t)(void __far *)static_functionality);
2191
2192 // A lot is a straight copy from the BDA. Note that the number
2193 // of character rows in the BDA is zero-based but one-based in
2194 // the dynamic state area
2195 memcpyb(ES,DI+0x04,BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,30);
2196 write_byte(ES,DI+0x22,read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1);
2197 memcpyb(ES,DI+0x23,BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,2);
2198
2199 write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
2200 write_byte(ES,DI+0x26,0); // Alternate display code
2201 write_word(ES,DI+0x27,16); // Number of colors
2202 write_byte(ES,DI+0x29,8); // Number of pages
2203 write_byte(ES,DI+0x2a,2); // Vertical resolution specifier
2204 write_byte(ES,DI+0x2b,0); // Primary font block
2205 write_byte(ES,DI+0x2c,0); // Secondary font block
2206 write_byte(ES,DI+0x2d,0x21);
2207 write_byte(ES,DI+0x31,3); // 256K video RAM
2208 write_byte(ES,DI+0x32,0); // Save pointer state information
2209
2210 mctl = read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
2211
2212 /* Extract and write the vertical resolution specifier bits. */
2213 scans = ((mctl & 0x80) >> 6) | ((mctl & 0x10) >> 4);
2214 switch (scans) {
2215 case 0: temp = 1; break; /* 350 lines */
2216 case 1: temp = 2; break; /* 400 lines */
2217 default:
2218 case 2: temp = 0; break; /* 200 lines */
2219 }
2220 write_byte(ES,DI+0x2a,temp);
2221
2222 /* Patch up the data for graphics modes. */
2223 if (mode >= 0x0E && mode <= 0x12) {
2224 if (pg_sz)
2225 write_byte(ES,DI+0x29,16384/(pg_sz >> 2));
2226 } else if (mode == 0x13) {
2227 write_byte(ES,DI+0x29,1); /* Just one page due to chaining */
2228 write_word(ES,DI+0x27,256); /* But 256!! colors!!! */
2229 } else if (mode >= 4 && mode <= 6) {
2230 /* CGA modes. */
2231 if (pg_sz)
2232 write_byte(ES,DI+0x29,16384/pg_sz);
2233 write_word(ES,DI+0x27,4);
2234 }
2235 if (mode == 6 || mode == 0x11)
2236 write_word(ES,DI+0x27,2); /* 2-color modes. */
2237
2238 if ((mode >= 4) && (mode != 7)) {
2239 write_byte(ES,DI+0x2d,0x01);
2240 scans = (read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1) * read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
2241 switch (scans) {
2242 case 200: temp = 0; break;
2243 case 350: temp = 1; break;
2244 case 400: temp = 2; break;
2245 default:
2246 case 480: temp = 3; break;
2247 }
2248 write_byte(ES,DI+0x2a,temp);
2249 }
2250
2251 memsetb(ES,DI+0x33,0,13);
2252}
2253
2254// --------------------------------------------------------------------------------------------
2255uint16_t biosfn_read_video_state_size2(uint16_t state)
2256{
2257 uint16_t size;
2258
2259 size = 0;
2260 if (state & 1)
2261 size += 0x46;
2262
2263 if (state & 2)
2264 size += (5 + 8 + 5) * 2 + 6;
2265
2266 if (state & 4)
2267 size += 3 + 256 * 3 + 1;
2268
2269 return size;
2270}
2271
2272static void vga_get_video_state_size(uint16_t state, uint16_t STACK_BASED *size)
2273{
2274 /* The size is the number of 64-byte blocks required to save the state. */
2275 *size = (biosfn_read_video_state_size2(state) + 63) / 64;
2276}
2277
2278uint16_t biosfn_save_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
2279{
2280 uint16_t i, crtc_addr, ar_index;
2281
2282 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
2283 if (CX & 1) {
2284 write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
2285 write_byte(ES, BX, inb(crtc_addr)); BX++;
2286 write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
2287 inb(VGAREG_ACTL_RESET);
2288 ar_index = inb(VGAREG_ACTL_ADDRESS);
2289 write_byte(ES, BX, ar_index); BX++;
2290 write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
2291
2292 for(i=1;i<=4;i++){
2293 outb(VGAREG_SEQU_ADDRESS, i);
2294 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
2295 }
2296 outb(VGAREG_SEQU_ADDRESS, 0);
2297 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
2298
2299 for(i=0;i<=0x18;i++) {
2300 outb(crtc_addr,i);
2301 write_byte(ES, BX, inb(crtc_addr+1)); BX++;
2302 }
2303
2304 for(i=0;i<=0x13;i++) {
2305 inb(VGAREG_ACTL_RESET); /* Reads do not toggle flip-flop! */
2306 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
2307 write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
2308 }
2309 inb(VGAREG_ACTL_RESET);
2310
2311 for(i=0;i<=8;i++) {
2312 outb(VGAREG_GRDC_ADDRESS,i);
2313 write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
2314 }
2315
2316 write_word(ES, BX, crtc_addr); BX+= 2;
2317
2318 /* XXX: read plane latches */
2319 write_byte(ES, BX, 0); BX++;
2320 write_byte(ES, BX, 0); BX++;
2321 write_byte(ES, BX, 0); BX++;
2322 write_byte(ES, BX, 0); BX++;
2323 }
2324 if (CX & 2) {
2325 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
2326 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
2327 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
2328 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
2329 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
2330 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
2331 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
2332 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
2333 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
2334 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
2335 for(i=0;i<8;i++) {
2336 write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
2337 BX += 2;
2338 }
2339 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
2340 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
2341 /* current font */
2342 write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
2343 write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
2344 write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
2345 write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
2346 }
2347 if (CX & 4) {
2348 /* XXX: check this */
2349 write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
2350 write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
2351 write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
2352 // Set the whole dac always, from 0
2353 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2354 for(i=0;i<256*3;i++) {
2355 write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
2356 }
2357 write_byte(ES, BX, 0); BX++; /* color select register */
2358 }
2359 return BX;
2360}
2361
2362uint16_t biosfn_restore_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
2363{
2364 uint16_t i, crtc_addr, v, addr1, ar_index;
2365
2366 if (CX & 1) {
2367 // Reset Attribute Ctl flip-flop
2368 inb(VGAREG_ACTL_RESET);
2369
2370 crtc_addr = read_word(ES, BX + 0x40);
2371 addr1 = BX;
2372 BX += 5;
2373
2374 for(i=1;i<=4;i++){
2375 outb(VGAREG_SEQU_ADDRESS, i);
2376 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
2377 }
2378 outb(VGAREG_SEQU_ADDRESS, 0);
2379 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
2380
2381 // select crtc base address
2382 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
2383 if (crtc_addr == 0x3d4)
2384 v |= 0x01;
2385 outb(VGAREG_WRITE_MISC_OUTPUT, v);
2386
2387 // Disable CRTC write protection
2388 outw(crtc_addr,0x0011);
2389 // Set CRTC regs
2390 for(i=0;i<=0x18;i++) {
2391 if (i != 0x11) {
2392 outb(crtc_addr,i);
2393 outb(crtc_addr+1, read_byte(ES, BX));
2394 }
2395 BX++;
2396 }
2397 // enable write protection if needed
2398 outb(crtc_addr, 0x11);
2399 outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
2400
2401 // Set Attribute Ctl
2402 ar_index = read_byte(ES, addr1 + 0x03);
2403 inb(VGAREG_ACTL_RESET);
2404 for(i=0;i<=0x13;i++) {
2405 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
2406 outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
2407 }
2408 outb(VGAREG_ACTL_ADDRESS, ar_index);
2409 inb(VGAREG_ACTL_RESET);
2410
2411 for(i=0;i<=8;i++) {
2412 outb(VGAREG_GRDC_ADDRESS,i);
2413 outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
2414 }
2415 BX += 2; /* crtc_addr */
2416 BX += 4; /* plane latches */
2417
2418 outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
2419 outb(crtc_addr, read_byte(ES, addr1)); addr1++;
2420 outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
2421 addr1++;
2422 outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
2423 }
2424 if (CX & 2) {
2425 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
2426 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
2427 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
2428 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
2429 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
2430 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
2431 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
2432 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
2433 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
2434 write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
2435 for(i=0;i<8;i++) {
2436 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
2437 BX += 2;
2438 }
2439 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
2440 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
2441 /* current font */
2442 write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
2443 write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
2444 write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
2445 write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
2446 }
2447 if (CX & 4) {
2448 BX++;
2449 v = read_byte(ES, BX); BX++;
2450 outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
2451 // Set the whole dac always, from 0
2452 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2453 for(i=0;i<256*3;i++) {
2454 outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
2455 }
2456 BX++;
2457 outb(VGAREG_DAC_WRITE_ADDRESS, v);
2458 }
2459 return BX;
2460}
2461
2462// ============================================================================================
2463//
2464// Video Utils
2465//
2466// ============================================================================================
2467
2468// --------------------------------------------------------------------------------------------
2469static uint8_t find_vga_entry(uint8_t mode)
2470{
2471 uint8_t i,line=0xFF;
2472 for(i=0;i<=MODE_MAX;i++)
2473 if(vga_modes[i].svgamode==mode)
2474 {line=i;
2475 break;
2476 }
2477 return line;
2478}
2479
2480/* =========================================================== */
2481/*
2482 * Misc Utils
2483*/
2484/* =========================================================== */
2485
2486/* This function is used for planar VGA memory reads to defeat the
2487 * optimizer. We must read exactly one byte, otherwise the screen
2488 * may be corrupted.
2489 */
2490uint8_t readx_byte(uint16_t seg, uint16_t offset)
2491{
2492 return( *(seg:>(uint8_t *)offset) );
2493}
2494
2495#ifdef VGA_DEBUG
2496void __cdecl unimplemented()
2497{
2498 printf("--> Unimplemented\n");
2499}
2500
2501void __cdecl unknown()
2502{
2503 printf("--> Unknown int10\n");
2504}
2505
2506#undef VBE_PRINTF_PORT
2507#define VBE_PRINTF_PORT 0x504
2508
2509// --------------------------------------------------------------------------------------------
2510void __cdecl printf(char *s, ...)
2511{
2512 char c;
2513 Boolean in_format;
2514 unsigned format_width, i;
2515 uint16_t arg, digit, nibble;
2516 uint16_t STACK_BASED *arg_ptr;
2517
2518 arg_ptr = (uint16_t STACK_BASED *)&s;
2519
2520 in_format = 0;
2521 format_width = 0;
2522
2523 while (c = *s) {
2524 if (c == '%') {
2525 in_format = 1;
2526 format_width = 0;
2527 } else if (in_format) {
2528 if ((c >= '0') && (c <= '9')) {
2529 format_width = (format_width * 10) + (c - '0');
2530 } else if (c == 'x') {
2531 arg_ptr++; // increment to next arg
2532 arg = *arg_ptr;
2533 if (format_width == 0)
2534 format_width = 4;
2535 i = 0;
2536 digit = format_width - 1;
2537 for (i = 0; i < format_width; i++) {
2538 nibble = (arg >> (4 * digit)) & 0x000f;
2539 if (nibble <= 9)
2540 outb(VBE_PRINTF_PORT, nibble + '0');
2541 else
2542 outb(VBE_PRINTF_PORT, (nibble - 10) + 'A');
2543 digit--;
2544 }
2545 in_format = 0;
2546 }
2547 //else if (c == 'd') {
2548 // in_format = 0;
2549 // }
2550 } else {
2551 outb(VBE_PRINTF_PORT, c);
2552 }
2553 ++s;
2554 }
2555}
2556#endif
2557
2558/// @todo rearrange, call only from VBE module?
2559extern void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI);
2560extern void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI);
2561extern void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI);
2562extern void vbe_biosfn_save_restore_state(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t DX, uint16_t ES, uint16_t STACK_BASED *BX);
2563extern void vbe_biosfn_get_set_scanline_length(uint16_t STACK_BASED *AX, uint16_t STACK_BASED *BX, uint16_t STACK_BASED *CX, uint16_t STACK_BASED *DX);
2564extern void private_biosfn_custom_mode(uint16_t STACK_BASED *AX, uint16_t STACK_BASED *BX, uint16_t STACK_BASED *CX, uint16_t STACK_BASED *DX);
2565
2566
2567// --------------------------------------------------------------------------------------------
2568/*
2569 * int10 main dispatcher
2570 */
2571void __cdecl int10_func(uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP, uint16_t BX,
2572 uint16_t DX, uint16_t CX, uint16_t AX, uint16_t DS, uint16_t ES, uint16_t FLAGS)
2573{
2574
2575 // BIOS functions
2576 switch(GET_AH())
2577 {
2578 case 0x00:
2579 biosfn_set_video_mode(GET_AL());
2580 switch(GET_AL()&0x7F)
2581 {case 6:
2582 SET_AL(0x3F);
2583 break;
2584 case 0:
2585 case 1:
2586 case 2:
2587 case 3:
2588 case 4:
2589 case 5:
2590 case 7:
2591 SET_AL(0x30);
2592 break;
2593 default:
2594 SET_AL(0x20);
2595 }
2596 break;
2597 case 0x01:
2598 biosfn_set_cursor_shape(GET_CH(),GET_CL());
2599 break;
2600 case 0x02:
2601 biosfn_set_cursor_pos(GET_BH(),DX);
2602 break;
2603 case 0x03:
2604 vga_get_cursor_pos(GET_BH(), &CX, &DX);
2605 break;
2606 case 0x04:
2607 // Read light pen pos (unimplemented)
2608#ifdef VGA_DEBUG
2609 unimplemented();
2610#endif
2611 AX=0x00;
2612 BX=0x00;
2613 CX=0x00;
2614 DX=0x00;
2615 break;
2616 case 0x05:
2617 biosfn_set_active_page(GET_AL());
2618 break;
2619 case 0x06:
2620 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
2621 break;
2622 case 0x07:
2623 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
2624 break;
2625 case 0x08:
2626 vga_read_char_attr(GET_BH(), &AX);
2627 break;
2628 case 0x09:
2629 biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
2630 break;
2631 case 0x0A:
2632 biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
2633 break;
2634 case 0x0C:
2635 biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
2636 break;
2637 case 0x0D:
2638 vga_read_pixel(GET_BH(), CX, DX, &AX);
2639 break;
2640 case 0x0E:
2641 // Ralf Brown Interrupt list is WRONG on bh(page)
2642 // We do output only on the current page !
2643#ifdef VGA_DEBUG
2644 printf("write_teletype %02x\n", GET_AL());
2645#endif
2646
2647 biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
2648 break;
2649 case 0x10:
2650 // All other functions of group AH=0x10 rewritten in assembler
2651 biosfn_perform_gray_scale_summing(BX,CX);
2652 break;
2653 case 0x11:
2654 switch(GET_AL())
2655 {
2656 case 0x00:
2657 case 0x10:
2658 biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
2659 break;
2660 case 0x01:
2661 case 0x11:
2662 biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
2663 break;
2664 case 0x02:
2665 case 0x12:
2666 biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
2667 break;
2668 case 0x03:
2669 biosfn_set_font_block(GET_BL());
2670 break;
2671 case 0x04:
2672 case 0x14:
2673 biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
2674 break;
2675 case 0x20:
2676 biosfn_load_gfx_8_8_chars(ES,BP);
2677 break;
2678 case 0x21:
2679 biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
2680 break;
2681 case 0x22:
2682 biosfn_load_gfx_8_14_chars(GET_BL(),GET_DL());
2683 break;
2684 case 0x23:
2685 biosfn_load_gfx_8_8_dd_chars(GET_BL(),GET_DL());
2686 break;
2687 case 0x24:
2688 biosfn_load_gfx_8_16_chars(GET_BL(),GET_DL());
2689 break;
2690 case 0x30:
2691 vga_get_font_info(GET_BH(), &ES, &BP, &CX, &DX);
2692 break;
2693#ifdef VGA_DEBUG
2694 default:
2695 unknown();
2696#endif
2697 }
2698
2699 break;
2700 case 0x12:
2701 switch(GET_BL())
2702 {
2703 case 0x20:
2704 biosfn_alternate_prtsc();
2705 break;
2706 case 0x30:
2707 if (GET_AL() <= 2) {
2708 biosfn_set_txt_lines(GET_AL());
2709 SET_AL(0x12);
2710 }
2711 break;
2712 case 0x34: /* CGA text cursor emulation control. */
2713 if (GET_AL() < 2) {
2714 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,
2715 (read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & ~1) | GET_AL());
2716 SET_AL(0x12);
2717 }
2718 else
2719 SET_AL(0); /* Invalid argument. */
2720 break;
2721 case 0x35:
2722 biosfn_switch_video_interface(GET_AL(),ES,DX);
2723 SET_AL(0x12);
2724 break;
2725 case 0x36:
2726 biosfn_enable_video_refresh_control(GET_AL());
2727 SET_AL(0x12);
2728 break;
2729#ifdef VGA_DEBUG
2730 default:
2731 unknown();
2732#endif
2733 }
2734 break;
2735 case 0x13:
2736 biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
2737 break;
2738 case 0x1B:
2739 biosfn_read_state_info(BX,ES,DI);
2740 SET_AL(0x1B);
2741 break;
2742 case 0x1C:
2743 switch(GET_AL())
2744 {
2745 case 0x00:
2746 vga_get_video_state_size(CX,&BX);
2747 break;
2748 case 0x01:
2749 biosfn_save_video_state(CX,ES,BX);
2750 break;
2751 case 0x02:
2752 biosfn_restore_video_state(CX,ES,BX);
2753 break;
2754#ifdef VGA_DEBUG
2755 default:
2756 unknown();
2757#endif
2758 }
2759 SET_AL(0x1C);
2760 break;
2761
2762#ifdef VBE
2763 case 0x4f:
2764 if (vbe_has_vbe_display()) {
2765 switch(GET_AL())
2766 {
2767 case 0x00:
2768 vbe_biosfn_return_controller_information(&AX,ES,DI);
2769 break;
2770 case 0x01:
2771 vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
2772 break;
2773 case 0x02:
2774 vbe_biosfn_set_mode(&AX,BX,ES,DI);
2775 break;
2776 case 0x04:
2777 vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
2778 break;
2779 case 0x06:
2780 vbe_biosfn_get_set_scanline_length(&AX, &BX, &CX, &DX);
2781 break;
2782 case 0x09:
2783 //FIXME
2784#ifdef VGA_DEBUG
2785 unimplemented();
2786#endif
2787 // function failed
2788 AX=0x100;
2789 break;
2790 case 0x0A:
2791 //FIXME
2792#ifdef VGA_DEBUG
2793 unimplemented();
2794#endif
2795 // function failed
2796 AX=0x100;
2797 break;
2798 default:
2799#ifdef VGA_DEBUG
2800 unknown();
2801#endif
2802 // function failed
2803 AX=0x100;
2804 }
2805 }
2806 else {
2807 // No VBE display
2808 AX=0x0100;
2809 }
2810 break;
2811 case 0x56:
2812 if (vbe_has_vbe_display()) {
2813 switch(GET_AL())
2814 {
2815 case 0x42:
2816 private_biosfn_custom_mode(&AX,&BX,&CX,&DX);
2817 break;
2818 default:
2819 AX=0x0100;
2820 break;
2821 }
2822 } else {
2823 // No VBE display
2824 AX=0x0100;
2825 }
2826 break;
2827#endif
2828
2829#ifdef VGA_DEBUG
2830 default:
2831 unknown();
2832#endif
2833 }
2834}
2835
2836#ifdef VBE
2837//#include "vbe.c"
2838#endif
2839
2840#ifdef CIRRUS
2841#include "clext.c"
2842#endif
2843
2844// --------------------------------------------------------------------------------------------
2845
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use