VirtualBox

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

Last change on this file since 97622 was 97622, checked in by vboxsync, 17 months ago

VGABIOS: Simplified/fixed font access routines; hopefully no behavioral change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.9 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_GRDC_ADDRESS, 0x0005);
1927 outb(VGAREG_GRDC_ADDRESS, 0x06);
1928 outw(VGAREG_GRDC_ADDRESS, (((0x04 | (inb(VGAREG_GRDC_DATA) & 0x01)) << 8) | 0x06));
1929 outw(VGAREG_SEQU_ADDRESS, 0x0402);
1930 outw(VGAREG_SEQU_ADDRESS, 0x0604);
1931}
1932
1933static void release_font_access(void)
1934{
1935 outw(VGAREG_GRDC_ADDRESS, (((0x0a | ((inb(VGAREG_READ_MISC_OUTPUT) & 0x01) << 2)) << 8) | 0x06));
1936 outw(VGAREG_GRDC_ADDRESS, 0x1005);
1937 outw(VGAREG_SEQU_ADDRESS, 0x0302);
1938 outw(VGAREG_SEQU_ADDRESS, 0x0204);
1939}
1940
1941static void set_scan_lines(uint8_t lines)
1942{
1943 uint16_t crtc_addr,cols,vde;
1944 uint8_t crtc_r9,ovl,rows;
1945
1946 crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
1947 outb(crtc_addr, 0x09);
1948 crtc_r9 = inb(crtc_addr+1);
1949 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
1950 outb(crtc_addr+1, crtc_r9);
1951 if(lines==8)
1952 {
1953 biosfn_set_cursor_shape(0x06,0x07);
1954 }
1955 else
1956 {
1957 biosfn_set_cursor_shape(lines-4,lines-3);
1958 }
1959 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
1960 outb(crtc_addr, 0x12);
1961 vde = inb(crtc_addr+1);
1962 outb(crtc_addr, 0x07);
1963 ovl = inb(crtc_addr+1);
1964 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
1965 rows = vde / lines;
1966 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
1967 cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1968 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
1969}
1970
1971static void biosfn_set_font_block(uint8_t BL)
1972{
1973 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1974 outw(VGAREG_SEQU_ADDRESS, 0x0003 | (BL << 8));
1975 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1976}
1977
1978static void biosfn_load_text_user_pat(uint8_t AL, uint16_t ES, uint16_t BP, uint16_t CX,
1979 uint16_t DX, uint8_t BL, uint8_t BH)
1980{
1981 uint16_t blockaddr,dest,i,src;
1982
1983 get_font_access();
1984 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1985 for(i=0;i<CX;i++)
1986 {
1987 src = BP + i * BH;
1988 dest = blockaddr + (DX + i) * 32;
1989 memcpyb(0xA000, dest, ES, src, BH);
1990 }
1991 release_font_access();
1992 if(AL>=0x10)
1993 {
1994 set_scan_lines(BH);
1995 }
1996}
1997
1998static void biosfn_load_text_8_14_pat(uint8_t AL, uint8_t BL)
1999{
2000 uint16_t blockaddr,dest,i,src;
2001
2002 get_font_access();
2003 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2004 for(i=0;i<0x100;i++)
2005 {
2006 src = i * 14;
2007 dest = blockaddr + i * 32;
2008 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont14+src, 14);
2009 }
2010 release_font_access();
2011 if(AL>=0x10)
2012 {
2013 set_scan_lines(14);
2014 }
2015}
2016
2017static void biosfn_load_text_8_8_pat(uint8_t AL, uint8_t BL)
2018{
2019 uint16_t blockaddr,dest,i,src;
2020
2021 get_font_access();
2022 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2023 for(i=0;i<0x100;i++)
2024 {
2025 src = i * 8;
2026 dest = blockaddr + i * 32;
2027 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont8+src, 8);
2028 }
2029 release_font_access();
2030 if(AL>=0x10)
2031 {
2032 set_scan_lines(8);
2033 }
2034}
2035
2036// --------------------------------------------------------------------------------------------
2037static void biosfn_load_text_8_16_pat(uint8_t AL, uint8_t BL)
2038{
2039 uint16_t blockaddr,dest,i,src;
2040
2041 get_font_access();
2042 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2043 for(i=0;i<0x100;i++)
2044 {
2045 src = i * 16;
2046 dest = blockaddr + i * 32;
2047 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont16+src, 16);
2048 }
2049 release_font_access();
2050 if(AL>=0x10)
2051 {
2052 set_scan_lines(16);
2053 }
2054}
2055
2056static void biosfn_load_gfx_8_8_chars(uint16_t ES, uint16_t BP)
2057{
2058 set_int_vector(0x1F, ES:>BP);
2059}
2060
2061static void set_gfx_font(void _far *font, uint16_t cheight, uint8_t row_code, uint8_t rows)
2062{
2063 static uint8_t row_tbl[] = { 0, 14, 25, 43 };
2064
2065 set_int_vector(0x43, font);
2066 if (row_code) {
2067 if (row_code > 3)
2068 row_code = 2; /* Default to 25 rows. */
2069 rows = row_tbl[row_code];
2070 }
2071 /* Else 'rows' used as is. */
2072
2073 write_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT, cheight);
2074 write_word(BIOSMEM_SEG, BIOSMEM_NB_ROWS, rows - 1);
2075}
2076
2077static void biosfn_load_gfx_user_chars(uint16_t ES, uint16_t BP, uint16_t CX,
2078 uint8_t BL, uint8_t DL)
2079{
2080 set_gfx_font(ES:>BP, CX, BL, DL);
2081}
2082
2083/* Some references (RBIL) suggest that only BL is used; that is wrong,
2084 * all of these subfunctions will use DL if BL is zero.
2085 */
2086static void biosfn_load_gfx_8_14_chars(uint8_t BL, uint8_t DL)
2087{
2088 set_gfx_font(vgafont14, 14, BL, DL);
2089}
2090static void biosfn_load_gfx_8_8_dd_chars(uint8_t BL, uint8_t DL)
2091{
2092 set_gfx_font(vgafont8, 8, BL, DL);
2093}
2094static void biosfn_load_gfx_8_16_chars(uint8_t BL, uint8_t DL)
2095{
2096 set_gfx_font(vgafont16, 16, BL, DL);
2097}
2098// --------------------------------------------------------------------------------------------
2099static void biosfn_alternate_prtsc(void)
2100{
2101#ifdef VGA_DEBUG
2102 unimplemented();
2103#endif
2104}
2105// --------------------------------------------------------------------------------------------
2106static void biosfn_set_txt_lines(uint8_t AL)
2107{
2108 uint8_t mctl;
2109
2110 /* Read byte at 40:89. */
2111 mctl = read_byte(BIOSMEM_SEG, BIOSMEM_MODESET_CTL);
2112 mctl = mctl & 0x6F; /* Clear 400/200 line flags. */
2113
2114 switch (AL) /* AL was already validated to be in 0-2 range. */
2115 {
2116 case 0: /* 200 lines. */
2117 mctl |= 0x80;
2118 break;
2119 case 2: /* 400 lines. */
2120 mctl |= 0x10;
2121 break;
2122 }
2123 write_byte(BIOSMEM_SEG, BIOSMEM_MODESET_CTL, mctl);
2124}
2125
2126// --------------------------------------------------------------------------------------------
2127static void biosfn_switch_video_interface (AL,ES,DX) uint8_t AL;uint16_t ES;uint16_t DX;
2128{
2129#ifdef VGA_DEBUG
2130 unimplemented();
2131#endif
2132}
2133static void biosfn_enable_video_refresh_control(uint8_t AL)
2134{
2135#ifdef VGA_DEBUG
2136 unimplemented();
2137#endif
2138}
2139
2140// --------------------------------------------------------------------------------------------
2141static void biosfn_write_string(uint8_t flag, uint8_t page, uint8_t attr, uint16_t count,
2142 uint8_t row, uint8_t col, uint16_t seg, uint16_t offset)
2143{
2144 uint16_t newcurs,oldcurs,dummy;
2145 uint8_t car;
2146
2147 // Read curs info for the page
2148 vga_get_cursor_pos(page,&dummy,&oldcurs);
2149
2150 // if row=0xff special case : use current cursor position
2151 if(row==0xff)
2152 {col=oldcurs&0x00ff;
2153 row=(oldcurs&0xff00)>>8;
2154 }
2155
2156 newcurs=row; newcurs<<=8; newcurs+=col;
2157 biosfn_set_cursor_pos(page,newcurs);
2158
2159 while(count--!=0)
2160 {
2161 car=read_byte(seg,offset++);
2162 if((flag&0x02)!=0)
2163 attr=read_byte(seg,offset++);
2164
2165 biosfn_write_teletype(car,page,attr,WITH_ATTR);
2166 }
2167
2168 // Set back curs pos
2169 if((flag&0x01)==0)
2170 biosfn_set_cursor_pos(page,oldcurs);
2171}
2172
2173// --------------------------------------------------------------------------------------------
2174static void biosfn_read_state_info(uint16_t BX, uint16_t ES, uint16_t DI)
2175{
2176 uint16_t pg_sz;
2177 uint16_t scans;
2178 uint8_t mode;
2179 uint8_t mctl;
2180 uint8_t temp;
2181
2182 mode = read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
2183 pg_sz = read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE);
2184 // Address of static functionality table
2185 write_dword(ES,DI+0x00, (uint32_t)(void __far *)static_functionality);
2186
2187 // A lot is a straight copy from the BDA. Note that the number
2188 // of character rows in the BDA is zero-based but one-based in
2189 // the dynamic state area
2190 memcpyb(ES,DI+0x04,BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,30);
2191 write_byte(ES,DI+0x22,read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1);
2192 memcpyb(ES,DI+0x23,BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,2);
2193
2194 write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
2195 write_byte(ES,DI+0x26,0); // Alternate display code
2196 write_word(ES,DI+0x27,16); // Number of colors
2197 write_byte(ES,DI+0x29,8); // Number of pages
2198 write_byte(ES,DI+0x2a,2); // Vertical resolution specifier
2199 write_byte(ES,DI+0x2b,0); // Primary font block
2200 write_byte(ES,DI+0x2c,0); // Secondary font block
2201 write_byte(ES,DI+0x2d,0x21);
2202 write_byte(ES,DI+0x31,3); // 256K video RAM
2203 write_byte(ES,DI+0x32,0); // Save pointer state information
2204
2205 mctl = read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
2206
2207 /* Extract and write the vertical resolution specifier bits. */
2208 scans = ((mctl & 0x80) >> 6) | ((mctl & 0x10) >> 4);
2209 switch (scans) {
2210 case 0: temp = 1; break; /* 350 lines */
2211 case 1: temp = 2; break; /* 400 lines */
2212 default:
2213 case 2: temp = 0; break; /* 200 lines */
2214 }
2215 write_byte(ES,DI+0x2a,temp);
2216
2217 /* Patch up the data for graphics modes. */
2218 if (mode >= 0x0E && mode <= 0x12) {
2219 if (pg_sz)
2220 write_byte(ES,DI+0x29,16384/(pg_sz >> 2));
2221 } else if (mode == 0x13) {
2222 write_byte(ES,DI+0x29,1); /* Just one page due to chaining */
2223 write_word(ES,DI+0x27,256); /* But 256!! colors!!! */
2224 } else if (mode >= 4 && mode <= 6) {
2225 /* CGA modes. */
2226 if (pg_sz)
2227 write_byte(ES,DI+0x29,16384/pg_sz);
2228 write_word(ES,DI+0x27,4);
2229 }
2230 if (mode == 6 || mode == 0x11)
2231 write_word(ES,DI+0x27,2); /* 2-color modes. */
2232
2233 if ((mode >= 4) && (mode != 7)) {
2234 write_byte(ES,DI+0x2d,0x01);
2235 scans = (read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1) * read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
2236 switch (scans) {
2237 case 200: temp = 0; break;
2238 case 350: temp = 1; break;
2239 case 400: temp = 2; break;
2240 default:
2241 case 480: temp = 3; break;
2242 }
2243 write_byte(ES,DI+0x2a,temp);
2244 }
2245
2246 memsetb(ES,DI+0x33,0,13);
2247}
2248
2249// --------------------------------------------------------------------------------------------
2250uint16_t biosfn_read_video_state_size2(uint16_t state)
2251{
2252 uint16_t size;
2253
2254 size = 0;
2255 if (state & 1)
2256 size += 0x46;
2257
2258 if (state & 2)
2259 size += (5 + 8 + 5) * 2 + 6;
2260
2261 if (state & 4)
2262 size += 3 + 256 * 3 + 1;
2263
2264 return size;
2265}
2266
2267static void vga_get_video_state_size(uint16_t state, uint16_t STACK_BASED *size)
2268{
2269 /* The size is the number of 64-byte blocks required to save the state. */
2270 *size = (biosfn_read_video_state_size2(state) + 63) / 64;
2271}
2272
2273uint16_t biosfn_save_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
2274{
2275 uint16_t i, crtc_addr, ar_index;
2276
2277 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
2278 if (CX & 1) {
2279 write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
2280 write_byte(ES, BX, inb(crtc_addr)); BX++;
2281 write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
2282 inb(VGAREG_ACTL_RESET);
2283 ar_index = inb(VGAREG_ACTL_ADDRESS);
2284 write_byte(ES, BX, ar_index); BX++;
2285 write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
2286
2287 for(i=1;i<=4;i++){
2288 outb(VGAREG_SEQU_ADDRESS, i);
2289 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
2290 }
2291 outb(VGAREG_SEQU_ADDRESS, 0);
2292 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
2293
2294 for(i=0;i<=0x18;i++) {
2295 outb(crtc_addr,i);
2296 write_byte(ES, BX, inb(crtc_addr+1)); BX++;
2297 }
2298
2299 for(i=0;i<=0x13;i++) {
2300 inb(VGAREG_ACTL_RESET); /* Reads do not toggle flip-flop! */
2301 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
2302 write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
2303 }
2304 inb(VGAREG_ACTL_RESET);
2305
2306 for(i=0;i<=8;i++) {
2307 outb(VGAREG_GRDC_ADDRESS,i);
2308 write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
2309 }
2310
2311 write_word(ES, BX, crtc_addr); BX+= 2;
2312
2313 /* XXX: read plane latches */
2314 write_byte(ES, BX, 0); BX++;
2315 write_byte(ES, BX, 0); BX++;
2316 write_byte(ES, BX, 0); BX++;
2317 write_byte(ES, BX, 0); BX++;
2318 }
2319 if (CX & 2) {
2320 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
2321 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
2322 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
2323 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
2324 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
2325 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
2326 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
2327 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
2328 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
2329 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
2330 for(i=0;i<8;i++) {
2331 write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
2332 BX += 2;
2333 }
2334 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
2335 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
2336 /* current font */
2337 write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
2338 write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
2339 write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
2340 write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
2341 }
2342 if (CX & 4) {
2343 /* XXX: check this */
2344 write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
2345 write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
2346 write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
2347 // Set the whole dac always, from 0
2348 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2349 for(i=0;i<256*3;i++) {
2350 write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
2351 }
2352 write_byte(ES, BX, 0); BX++; /* color select register */
2353 }
2354 return BX;
2355}
2356
2357uint16_t biosfn_restore_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
2358{
2359 uint16_t i, crtc_addr, v, addr1, ar_index;
2360
2361 if (CX & 1) {
2362 // Reset Attribute Ctl flip-flop
2363 inb(VGAREG_ACTL_RESET);
2364
2365 crtc_addr = read_word(ES, BX + 0x40);
2366 addr1 = BX;
2367 BX += 5;
2368
2369 for(i=1;i<=4;i++){
2370 outb(VGAREG_SEQU_ADDRESS, i);
2371 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
2372 }
2373 outb(VGAREG_SEQU_ADDRESS, 0);
2374 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
2375
2376 // select crtc base address
2377 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
2378 if (crtc_addr == 0x3d4)
2379 v |= 0x01;
2380 outb(VGAREG_WRITE_MISC_OUTPUT, v);
2381
2382 // Disable CRTC write protection
2383 outw(crtc_addr,0x0011);
2384 // Set CRTC regs
2385 for(i=0;i<=0x18;i++) {
2386 if (i != 0x11) {
2387 outb(crtc_addr,i);
2388 outb(crtc_addr+1, read_byte(ES, BX));
2389 }
2390 BX++;
2391 }
2392 // enable write protection if needed
2393 outb(crtc_addr, 0x11);
2394 outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
2395
2396 // Set Attribute Ctl
2397 ar_index = read_byte(ES, addr1 + 0x03);
2398 inb(VGAREG_ACTL_RESET);
2399 for(i=0;i<=0x13;i++) {
2400 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
2401 outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
2402 }
2403 outb(VGAREG_ACTL_ADDRESS, ar_index);
2404 inb(VGAREG_ACTL_RESET);
2405
2406 for(i=0;i<=8;i++) {
2407 outb(VGAREG_GRDC_ADDRESS,i);
2408 outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
2409 }
2410 BX += 2; /* crtc_addr */
2411 BX += 4; /* plane latches */
2412
2413 outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
2414 outb(crtc_addr, read_byte(ES, addr1)); addr1++;
2415 outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
2416 addr1++;
2417 outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
2418 }
2419 if (CX & 2) {
2420 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
2421 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
2422 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
2423 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
2424 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
2425 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
2426 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
2427 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
2428 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
2429 write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
2430 for(i=0;i<8;i++) {
2431 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
2432 BX += 2;
2433 }
2434 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
2435 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
2436 /* current font */
2437 write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
2438 write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
2439 write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
2440 write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
2441 }
2442 if (CX & 4) {
2443 BX++;
2444 v = read_byte(ES, BX); BX++;
2445 outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
2446 // Set the whole dac always, from 0
2447 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2448 for(i=0;i<256*3;i++) {
2449 outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
2450 }
2451 BX++;
2452 outb(VGAREG_DAC_WRITE_ADDRESS, v);
2453 }
2454 return BX;
2455}
2456
2457// ============================================================================================
2458//
2459// Video Utils
2460//
2461// ============================================================================================
2462
2463// --------------------------------------------------------------------------------------------
2464static uint8_t find_vga_entry(uint8_t mode)
2465{
2466 uint8_t i,line=0xFF;
2467 for(i=0;i<=MODE_MAX;i++)
2468 if(vga_modes[i].svgamode==mode)
2469 {line=i;
2470 break;
2471 }
2472 return line;
2473}
2474
2475/* =========================================================== */
2476/*
2477 * Misc Utils
2478*/
2479/* =========================================================== */
2480
2481/* This function is used for planar VGA memory reads to defeat the
2482 * optimizer. We must read exactly one byte, otherwise the screen
2483 * may be corrupted.
2484 */
2485uint8_t readx_byte(uint16_t seg, uint16_t offset)
2486{
2487 return( *(seg:>(uint8_t *)offset) );
2488}
2489
2490#ifdef VGA_DEBUG
2491void __cdecl unimplemented()
2492{
2493 printf("--> Unimplemented\n");
2494}
2495
2496void __cdecl unknown()
2497{
2498 printf("--> Unknown int10\n");
2499}
2500
2501#undef VBE_PRINTF_PORT
2502#define VBE_PRINTF_PORT 0x504
2503
2504// --------------------------------------------------------------------------------------------
2505void __cdecl printf(char *s, ...)
2506{
2507 char c;
2508 Boolean in_format;
2509 unsigned format_width, i;
2510 uint16_t arg, digit, nibble;
2511 uint16_t STACK_BASED *arg_ptr;
2512
2513 arg_ptr = (uint16_t STACK_BASED *)&s;
2514
2515 in_format = 0;
2516 format_width = 0;
2517
2518 while (c = *s) {
2519 if (c == '%') {
2520 in_format = 1;
2521 format_width = 0;
2522 } else if (in_format) {
2523 if ((c >= '0') && (c <= '9')) {
2524 format_width = (format_width * 10) + (c - '0');
2525 } else if (c == 'x') {
2526 arg_ptr++; // increment to next arg
2527 arg = *arg_ptr;
2528 if (format_width == 0)
2529 format_width = 4;
2530 i = 0;
2531 digit = format_width - 1;
2532 for (i = 0; i < format_width; i++) {
2533 nibble = (arg >> (4 * digit)) & 0x000f;
2534 if (nibble <= 9)
2535 outb(VBE_PRINTF_PORT, nibble + '0');
2536 else
2537 outb(VBE_PRINTF_PORT, (nibble - 10) + 'A');
2538 digit--;
2539 }
2540 in_format = 0;
2541 }
2542 //else if (c == 'd') {
2543 // in_format = 0;
2544 // }
2545 } else {
2546 outb(VBE_PRINTF_PORT, c);
2547 }
2548 ++s;
2549 }
2550}
2551#endif
2552
2553/// @todo rearrange, call only from VBE module?
2554extern void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI);
2555extern void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI);
2556extern void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI);
2557extern 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);
2558extern 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);
2559extern 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);
2560
2561
2562// --------------------------------------------------------------------------------------------
2563/*
2564 * int10 main dispatcher
2565 */
2566void __cdecl int10_func(uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP, uint16_t BX,
2567 uint16_t DX, uint16_t CX, uint16_t AX, uint16_t DS, uint16_t ES, uint16_t FLAGS)
2568{
2569
2570 // BIOS functions
2571 switch(GET_AH())
2572 {
2573 case 0x00:
2574 biosfn_set_video_mode(GET_AL());
2575 switch(GET_AL()&0x7F)
2576 {case 6:
2577 SET_AL(0x3F);
2578 break;
2579 case 0:
2580 case 1:
2581 case 2:
2582 case 3:
2583 case 4:
2584 case 5:
2585 case 7:
2586 SET_AL(0x30);
2587 break;
2588 default:
2589 SET_AL(0x20);
2590 }
2591 break;
2592 case 0x01:
2593 biosfn_set_cursor_shape(GET_CH(),GET_CL());
2594 break;
2595 case 0x02:
2596 biosfn_set_cursor_pos(GET_BH(),DX);
2597 break;
2598 case 0x03:
2599 vga_get_cursor_pos(GET_BH(), &CX, &DX);
2600 break;
2601 case 0x04:
2602 // Read light pen pos (unimplemented)
2603#ifdef VGA_DEBUG
2604 unimplemented();
2605#endif
2606 AX=0x00;
2607 BX=0x00;
2608 CX=0x00;
2609 DX=0x00;
2610 break;
2611 case 0x05:
2612 biosfn_set_active_page(GET_AL());
2613 break;
2614 case 0x06:
2615 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
2616 break;
2617 case 0x07:
2618 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
2619 break;
2620 case 0x08:
2621 vga_read_char_attr(GET_BH(), &AX);
2622 break;
2623 case 0x09:
2624 biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
2625 break;
2626 case 0x0A:
2627 biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
2628 break;
2629 case 0x0C:
2630 biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
2631 break;
2632 case 0x0D:
2633 vga_read_pixel(GET_BH(), CX, DX, &AX);
2634 break;
2635 case 0x0E:
2636 // Ralf Brown Interrupt list is WRONG on bh(page)
2637 // We do output only on the current page !
2638#ifdef VGA_DEBUG
2639 printf("write_teletype %02x\n", GET_AL());
2640#endif
2641
2642 biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
2643 break;
2644 case 0x10:
2645 // All other functions of group AH=0x10 rewritten in assembler
2646 biosfn_perform_gray_scale_summing(BX,CX);
2647 break;
2648 case 0x11:
2649 switch(GET_AL())
2650 {
2651 case 0x00:
2652 case 0x10:
2653 biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
2654 break;
2655 case 0x01:
2656 case 0x11:
2657 biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
2658 break;
2659 case 0x02:
2660 case 0x12:
2661 biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
2662 break;
2663 case 0x03:
2664 biosfn_set_font_block(GET_BL());
2665 break;
2666 case 0x04:
2667 case 0x14:
2668 biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
2669 break;
2670 case 0x20:
2671 biosfn_load_gfx_8_8_chars(ES,BP);
2672 break;
2673 case 0x21:
2674 biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
2675 break;
2676 case 0x22:
2677 biosfn_load_gfx_8_14_chars(GET_BL(),GET_DL());
2678 break;
2679 case 0x23:
2680 biosfn_load_gfx_8_8_dd_chars(GET_BL(),GET_DL());
2681 break;
2682 case 0x24:
2683 biosfn_load_gfx_8_16_chars(GET_BL(),GET_DL());
2684 break;
2685 case 0x30:
2686 vga_get_font_info(GET_BH(), &ES, &BP, &CX, &DX);
2687 break;
2688#ifdef VGA_DEBUG
2689 default:
2690 unknown();
2691#endif
2692 }
2693
2694 break;
2695 case 0x12:
2696 switch(GET_BL())
2697 {
2698 case 0x20:
2699 biosfn_alternate_prtsc();
2700 break;
2701 case 0x30:
2702 if (GET_AL() <= 2) {
2703 biosfn_set_txt_lines(GET_AL());
2704 SET_AL(0x12);
2705 }
2706 break;
2707 case 0x34: /* CGA text cursor emulation control. */
2708 if (GET_AL() < 2) {
2709 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,
2710 (read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & ~1) | GET_AL());
2711 SET_AL(0x12);
2712 }
2713 else
2714 SET_AL(0); /* Invalid argument. */
2715 break;
2716 case 0x35:
2717 biosfn_switch_video_interface(GET_AL(),ES,DX);
2718 SET_AL(0x12);
2719 break;
2720 case 0x36:
2721 biosfn_enable_video_refresh_control(GET_AL());
2722 SET_AL(0x12);
2723 break;
2724#ifdef VGA_DEBUG
2725 default:
2726 unknown();
2727#endif
2728 }
2729 break;
2730 case 0x13:
2731 biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
2732 break;
2733 case 0x1B:
2734 biosfn_read_state_info(BX,ES,DI);
2735 SET_AL(0x1B);
2736 break;
2737 case 0x1C:
2738 switch(GET_AL())
2739 {
2740 case 0x00:
2741 vga_get_video_state_size(CX,&BX);
2742 break;
2743 case 0x01:
2744 biosfn_save_video_state(CX,ES,BX);
2745 break;
2746 case 0x02:
2747 biosfn_restore_video_state(CX,ES,BX);
2748 break;
2749#ifdef VGA_DEBUG
2750 default:
2751 unknown();
2752#endif
2753 }
2754 SET_AL(0x1C);
2755 break;
2756
2757#ifdef VBE
2758 case 0x4f:
2759 if (vbe_has_vbe_display()) {
2760 switch(GET_AL())
2761 {
2762 case 0x00:
2763 vbe_biosfn_return_controller_information(&AX,ES,DI);
2764 break;
2765 case 0x01:
2766 vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
2767 break;
2768 case 0x02:
2769 vbe_biosfn_set_mode(&AX,BX,ES,DI);
2770 break;
2771 case 0x04:
2772 vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
2773 break;
2774 case 0x06:
2775 vbe_biosfn_get_set_scanline_length(&AX, &BX, &CX, &DX);
2776 break;
2777 case 0x09:
2778 //FIXME
2779#ifdef VGA_DEBUG
2780 unimplemented();
2781#endif
2782 // function failed
2783 AX=0x100;
2784 break;
2785 case 0x0A:
2786 //FIXME
2787#ifdef VGA_DEBUG
2788 unimplemented();
2789#endif
2790 // function failed
2791 AX=0x100;
2792 break;
2793 default:
2794#ifdef VGA_DEBUG
2795 unknown();
2796#endif
2797 // function failed
2798 AX=0x100;
2799 }
2800 }
2801 else {
2802 // No VBE display
2803 AX=0x0100;
2804 }
2805 break;
2806 case 0x56:
2807 if (vbe_has_vbe_display()) {
2808 switch(GET_AL())
2809 {
2810 case 0x42:
2811 private_biosfn_custom_mode(&AX,&BX,&CX,&DX);
2812 break;
2813 default:
2814 AX=0x0100;
2815 break;
2816 }
2817 } else {
2818 // No VBE display
2819 AX=0x0100;
2820 }
2821 break;
2822#endif
2823
2824#ifdef VGA_DEBUG
2825 default:
2826 unknown();
2827#endif
2828 }
2829}
2830
2831#ifdef VBE
2832//#include "vbe.c"
2833#endif
2834
2835#ifdef CIRRUS
2836#include "clext.c"
2837#endif
2838
2839// --------------------------------------------------------------------------------------------
2840
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use