VirtualBox

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

Last change on this file since 94251 was 93873, checked in by vboxsync, 3 years ago

VGABIOS: Implemented INT 10h/112xH functions (graphical font set).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.2 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// - [email protected]
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
902static 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);
903
904void biosfn_set_video_mode(uint8_t mode)
905{// mode: Bit 7 is 1 if no clear screen
906
907 // Should we clear the screen ?
908 uint8_t noclearmem=mode&0x80;
909 uint8_t line,mmask,vpti;
910 uint8_t modeset_ctl;
911 uint8_t *palette;
912 uint16_t i;
913 uint16_t crtc_addr;
914 void __far * __far *save_area;
915 VideoParamTableEntry __far *vpt;
916
917#ifdef VBE
918 if (vbe_has_vbe_display()) {
919 // Force controller into VGA mode
920 outb(VGAREG_SEQU_ADDRESS,7);
921 outb(VGAREG_SEQU_DATA,0x00);
922 }
923#endif // def VBE
924
925 // The real mode
926 mode=mode&0x7f;
927
928 // Display switching is not supported; mono monitors aren't really either,
929 // but requests to set mode 7 are honored.
930
931 // find the entry in the video modes
932 line=find_vga_entry(mode);
933
934#ifdef VGA_DEBUG
935 printf("mode search %02x found line %02x\n",mode,line);
936#endif
937
938 if(line==0xFF)
939 return;
940
941 // Read the save area pointer.
942 save_area = (void __far *)read_dword(BIOSMEM_SEG, BIOSMEM_VS_POINTER);
943
944 vpti=line_to_vpti[line];
945 vpt = save_area[0];
946 vpt += vpti;
947
948#if 0 // These are unused, but perhaps they shouldn't be?
949 // Read the bios vga control
950 video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
951
952 // Read the bios vga switches
953 vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
954#endif
955
956 // Read the bios mode set control
957 modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
958
959 // Then we know the number of lines
960// FIXME
961
962 // if palette loading (bit 3 of modeset ctl = 0)
963 if((modeset_ctl&0x08)==0)
964 {// Set the PEL mask
965 outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
966
967 // Set the whole dac always, from 0
968 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
969
970 // From which palette
971 switch(vga_modes[line].dacmodel)
972 {case 0:
973 palette=&palette0[0];
974 break;
975 case 1:
976 palette=&palette1[0];
977 break;
978 case 2:
979 palette=&palette2[0];
980 break;
981 case 3:
982 palette=&palette3[0];
983 break;
984 }
985 // Always 256*3 values
986 for(i=0;i<0x0100;i++)
987 {if(i<=dac_regs[vga_modes[line].dacmodel])
988 {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
989 outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
990 outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
991 }
992 else
993 {outb(VGAREG_DAC_DATA,0);
994 outb(VGAREG_DAC_DATA,0);
995 outb(VGAREG_DAC_DATA,0);
996 }
997 }
998 if((modeset_ctl&0x02)==0x02)
999 {
1000 biosfn_perform_gray_scale_summing(0x00, 0x100);
1001 }
1002 }
1003
1004 // Reset Attribute Ctl flip-flop
1005 inb(VGAREG_ACTL_RESET);
1006
1007 // Set Attribute Ctl
1008 for(i=0;i<=0x13;i++)
1009 {outb(VGAREG_ACTL_ADDRESS,i);
1010 outb(VGAREG_ACTL_WRITE_DATA,vpt->actl_regs[i]);
1011 }
1012 outb(VGAREG_ACTL_ADDRESS,0x14);
1013 outb(VGAREG_ACTL_WRITE_DATA,0x00);
1014
1015 save_area[0] = video_param_table;
1016
1017 // Save palette into the save area if it exists.
1018 if(save_area[1])
1019 {
1020 uint8_t __far *dyn_save;
1021
1022 dyn_save = save_area[1];
1023 for (i = 0; i < 16; ++i)
1024 dyn_save[i] = vpt->actl_regs[i];
1025 dyn_save[16] = vpt->actl_regs[17];
1026 }
1027
1028 // Set Sequencer Ctl
1029 outb(VGAREG_SEQU_ADDRESS,0);
1030 outb(VGAREG_SEQU_DATA,0x03);
1031 for(i=1;i<=4;i++)
1032 {outb(VGAREG_SEQU_ADDRESS,i);
1033 outb(VGAREG_SEQU_DATA,vpt->sequ_regs[i - 1]);
1034 }
1035
1036 // Set Grafx Ctl
1037 for(i=0;i<=8;i++)
1038 {outb(VGAREG_GRDC_ADDRESS,i);
1039 outb(VGAREG_GRDC_DATA,vpt->grdc_regs[i]);
1040 }
1041
1042 // Set CRTC address VGA or MDA
1043 crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
1044
1045 // Set the misc register; may change CRTC base!
1046 outb(VGAREG_WRITE_MISC_OUTPUT,vpt->miscreg);
1047
1048 // Disable CRTC write protection
1049 outw(crtc_addr,0x0011);
1050 // Set CRTC regs
1051 for(i=0;i<=0x18;i++)
1052 {outb(crtc_addr,i);
1053 outb(crtc_addr+1,vpt->crtc_regs[i]);
1054 }
1055
1056 // Enable video
1057 outb(VGAREG_ACTL_ADDRESS,0x20);
1058 inb(crtc_addr + VGAREG_ACTL_RESET - VGAREG_VGA_CRTC_ADDRESS);
1059
1060 if(noclearmem==0x00)
1061 {
1062 if(vga_modes[line].class==TEXT)
1063 {
1064 memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
1065 }
1066 else
1067 {
1068 if(mode<0x0d)
1069 {
1070 memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
1071 }
1072 else
1073 {
1074 outb( VGAREG_SEQU_ADDRESS, 0x02 );
1075 mmask = inb( VGAREG_SEQU_DATA );
1076 outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
1077 memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
1078 outb( VGAREG_SEQU_DATA, mmask );
1079 }
1080 }
1081 }
1082
1083 // Set the BIOS mem
1084 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
1085 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,vpt->twidth);
1086 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vpt->slength);
1087 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
1088 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,vpt->theightm1);
1089 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,vpt->cheight);
1090 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
1091 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
1092 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
1093
1094 // FIXME We nearly have the good tables. to be reworked
1095 write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
1096
1097 if (mode <= 7)
1098 {
1099 write_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MSR, cga_msr[mode]); /* Like CGA reg. 0x3D8 */
1100 write_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_PAL, mode == 6 ? 0x3F : 0x30); /* Like CGA reg. 0x3D9*/
1101 }
1102
1103 // Set cursor shape
1104 if(vga_modes[line].class==TEXT)
1105 {
1106 biosfn_set_cursor_shape(0x06,0x07);
1107 }
1108
1109 /// @todo Could be optimized to a memset since only BDA needs updating.
1110 // Set cursor pos for page 0..7
1111 for(i=0;i<8;i++)
1112 biosfn_set_cursor_pos(i,0x0000);
1113
1114 // Set active page 0
1115 biosfn_set_active_page(0x00);
1116
1117 // Write the fonts in memory
1118 if(vga_modes[line].class==TEXT)
1119 {
1120 cso_txt __far *ovr = save_area[2];
1121
1122 biosfn_load_text_8_16_pat(0x04, 0); /* Load 8x16 font into page 0. */
1123 if (ovr)
1124 {
1125#ifdef VGA_DEBUG
1126 printf("Charmap override found, font at %04x:%04x\n", ovr->font_seg, ovr->font_ofs);
1127#endif
1128 i = 0;
1129 // Does the override support current mode?
1130 while (ovr->modes[i] != 0xff)
1131 {
1132 if (ovr->modes[i] == mode)
1133 break;
1134 ++i;
1135 }
1136 // If there is a valid font override, apply it.
1137 if (ovr->modes[i] == mode)
1138 {
1139#ifdef VGA_DEBUG
1140 printf("Loading override, %04x chars, height %02x\n", ovr->char_num, ovr->c_height);
1141#endif
1142 biosfn_load_text_user_pat(0x10, ovr->font_seg, ovr->font_ofs, ovr->char_num,
1143 ovr->char_1st, ovr->cgen_bank, ovr->c_height);
1144 }
1145 }
1146 vga_font_set(0x03, 0); /* Select font page mode 0. */
1147 }
1148
1149 // Set the ints 0x1F and 0x43
1150 set_int_vector(0x1f, vgafont8+128*8);
1151
1152 switch(vpt->cheight)
1153 {case 8:
1154 set_int_vector(0x43, vgafont8);
1155 break;
1156 case 14:
1157 set_int_vector(0x43, vgafont14);
1158 break;
1159 case 16:
1160 set_int_vector(0x43, vgafont16);
1161 break;
1162 }
1163}
1164
1165// --------------------------------------------------------------------------------------------
1166static void vgamem_copy_pl4(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
1167 uint8_t cols, uint8_t nbcols, uint8_t cheight)
1168{
1169 uint16_t src,dest;
1170 uint8_t i;
1171
1172 src=ysrc*cheight*nbcols+xstart;
1173 dest=ydest*cheight*nbcols+xstart;
1174 outw(VGAREG_GRDC_ADDRESS, 0x0105);
1175 for(i=0;i<cheight;i++)
1176 {
1177 memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
1178 }
1179 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1180}
1181
1182// --------------------------------------------------------------------------------------------
1183static void vgamem_fill_pl4(uint8_t xstart, uint8_t ystart, uint8_t cols,
1184 uint8_t nbcols, uint8_t cheight, uint8_t attr)
1185{
1186 uint16_t dest;
1187 uint8_t i;
1188
1189 dest=ystart*cheight*nbcols+xstart;
1190 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1191 for(i=0;i<cheight;i++)
1192 {
1193 memsetb(0xa000,dest+i*nbcols,attr,cols);
1194 }
1195 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1196}
1197
1198// --------------------------------------------------------------------------------------------
1199static void vgamem_copy_cga(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
1200 uint8_t cols, uint8_t nbcols, uint8_t cheight)
1201{
1202 uint16_t src,dest;
1203 uint8_t i;
1204
1205 src=((ysrc*cheight*nbcols)>>1)+xstart;
1206 dest=((ydest*cheight*nbcols)>>1)+xstart;
1207 for(i=0;i<cheight/2;i++)
1208 {
1209 memcpyb(0xb800,dest+i*nbcols,0xb800,src+i*nbcols,cols);
1210 memcpyb(0xb800,0x2000+dest+i*nbcols,0xb800,0x2000+src+i*nbcols,cols);
1211 }
1212}
1213
1214// --------------------------------------------------------------------------------------------
1215static void vgamem_fill_cga(uint8_t xstart, uint8_t ystart, uint8_t cols,
1216 uint8_t nbcols, uint8_t cheight, uint8_t attr)
1217{
1218 uint16_t dest;
1219 uint8_t i;
1220
1221 dest=((ystart*cheight*nbcols)>>1)+xstart;
1222 for(i=0;i<cheight/2;i++)
1223 {
1224 memsetb(0xb800,dest+i*nbcols,attr,cols);
1225 memsetb(0xb800,0x2000+dest+i*nbcols,attr,cols);
1226 }
1227}
1228
1229// --------------------------------------------------------------------------------------------
1230static void vgamem_copy_linear(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
1231 uint16_t cols, uint16_t nbcols, uint8_t cheight)
1232{
1233 uint16_t src,dest;
1234 uint8_t i;
1235
1236 src=((ysrc*cheight*nbcols)+xstart)*8;
1237 dest=((ydest*cheight*nbcols)+xstart)*8;
1238 cols*=8;
1239 nbcols*=8;
1240 for(i=0;i<cheight;i++)
1241 {
1242 memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
1243 }
1244}
1245
1246// --------------------------------------------------------------------------------------------
1247static void vgamem_fill_linear(uint8_t xstart, uint8_t ystart, uint16_t cols,
1248 uint16_t nbcols, uint8_t cheight, uint8_t attr)
1249{
1250 uint16_t dest;
1251 uint8_t i;
1252
1253 dest=((ystart*cheight*nbcols)+xstart)*8;
1254 cols*=8;
1255 nbcols*=8;
1256 for(i=0;i<cheight;i++)
1257 {
1258 memsetb(0xa000,dest+i*nbcols,attr,cols);
1259 }
1260}
1261
1262// --------------------------------------------------------------------------------------------
1263static void biosfn_scroll(uint8_t nblines, uint8_t attr, uint8_t rul, uint8_t cul,
1264 uint8_t rlr, uint8_t clr, uint8_t page, uint8_t dir)
1265{
1266 // page == 0xFF if current
1267
1268 uint8_t mode,line,cheight,bpp,cols;
1269 uint16_t nbcols,nbrows,i;
1270 uint16_t address;
1271
1272 if(rul>rlr)return;
1273 if(cul>clr)return;
1274
1275 // Get the mode
1276 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1277 line=find_vga_entry(mode);
1278 if(line==0xFF)return;
1279
1280 // Get the dimensions
1281 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1282 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1283
1284 // Get the current page
1285 if(page==0xFF)
1286 page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
1287
1288 if(rlr>=nbrows)rlr=nbrows-1;
1289 if(clr>=nbcols)clr=nbcols-1;
1290 if(nblines>nbrows)nblines=0;
1291 cols=clr-cul+1;
1292
1293 if(vga_modes[line].class==TEXT)
1294 {
1295 // Compute the address
1296 address=SCREEN_MEM_START(nbcols,nbrows,page);
1297#ifdef VGA_DEBUG
1298 printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
1299#endif
1300
1301 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1302 {
1303 memsetw(vga_modes[line].sstart,address,(uint16_t)attr*0x100+' ',nbrows*nbcols);
1304 }
1305 else
1306 {// if Scroll up
1307 if(dir==SCROLL_UP)
1308 {for(i=rul;i<=rlr;i++)
1309 {
1310 if((i+nblines>rlr)||(nblines==0))
1311 memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(uint16_t)attr*0x100+' ',cols);
1312 else
1313 memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
1314 }
1315 }
1316 else
1317 {for(i=rlr;i>=rul;i--)
1318 {
1319 if((i<rul+nblines)||(nblines==0))
1320 memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(uint16_t)attr*0x100+' ',cols);
1321 else
1322 memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
1323 if (i>rlr) break;
1324 }
1325 }
1326 }
1327 }
1328 else
1329 {
1330 cheight=video_param_table[line_to_vpti[line]].cheight;
1331 switch(vga_modes[line].memmodel)
1332 {
1333 case PLANAR4:
1334 case PLANAR1:
1335 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1336 {
1337 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1338 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
1339 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1340 }
1341 else
1342 {// if Scroll up
1343 if(dir==SCROLL_UP)
1344 {for(i=rul;i<=rlr;i++)
1345 {
1346 if((i+nblines>rlr)||(nblines==0))
1347 vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
1348 else
1349 vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
1350 }
1351 }
1352 else
1353 {for(i=rlr;i>=rul;i--)
1354 {
1355 if((i<rul+nblines)||(nblines==0))
1356 vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
1357 else
1358 vgamem_copy_pl4(cul,i-nblines,i,cols,nbcols,cheight);
1359 if (i>rlr) break;
1360 }
1361 }
1362 }
1363 break;
1364 case CGA:
1365 bpp=vga_modes[line].pixbits;
1366 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1367 {
1368 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
1369 }
1370 else
1371 {
1372 if(bpp==2)
1373 {
1374 cul<<=1;
1375 cols<<=1;
1376 nbcols<<=1;
1377 }
1378 // if Scroll up
1379 if(dir==SCROLL_UP)
1380 {for(i=rul;i<=rlr;i++)
1381 {
1382 if((i+nblines>rlr)||(nblines==0))
1383 vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
1384 else
1385 vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
1386 }
1387 }
1388 else
1389 {for(i=rlr;i>=rul;i--)
1390 {
1391 if((i<rul+nblines)||(nblines==0))
1392 vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
1393 else
1394 vgamem_copy_cga(cul,i-nblines,i,cols,nbcols,cheight);
1395 if (i>rlr) break;
1396 }
1397 }
1398 }
1399 break;
1400 case LINEAR8:
1401 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1402 {
1403 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*8);
1404 }
1405 else
1406 {
1407 // if Scroll up
1408 if(dir==SCROLL_UP)
1409 {for(i=rul;i<=rlr;i++)
1410 {
1411 if((i+nblines>rlr)||(nblines==0))
1412 vgamem_fill_linear(cul,i,cols,nbcols,cheight,attr);
1413 else
1414 vgamem_copy_linear(cul,i+nblines,i,cols,nbcols,cheight);
1415 }
1416 }
1417 else
1418 {for(i=rlr;i>=rul;i--)
1419 {
1420 if((i<rul+nblines)||(nblines==0))
1421 vgamem_fill_linear(cul,i,cols,nbcols,cheight,attr);
1422 else
1423 vgamem_copy_linear(cul,i-nblines,i,cols,nbcols,cheight);
1424 if (i>rlr) break;
1425 }
1426 }
1427 }
1428 break;
1429#ifdef VGA_DEBUG
1430 default:
1431 printf("Scroll in graphics mode ");
1432 unimplemented();
1433#endif
1434 }
1435 }
1436}
1437
1438// --------------------------------------------------------------------------------------------
1439static void write_gfx_char_pl4(uint8_t car, uint8_t attr, uint8_t xcurs,
1440 uint8_t ycurs, uint8_t nbcols, uint8_t cheight, uint8_t page)
1441{
1442 uint8_t i,j,mask;
1443 uint8_t __far *fdata;
1444 uint16_t addr,dest,src;
1445
1446 fdata = (void __far *)read_dword(0x00, 0x43 * 4);
1447
1448 addr=xcurs+ycurs*cheight*nbcols;
1449 addr+=read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)*page;
1450 src = car * cheight;
1451 outw(VGAREG_SEQU_ADDRESS, 0x0f02);
1452 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1453 if(attr&0x80)
1454 {
1455 outw(VGAREG_GRDC_ADDRESS, 0x1803);
1456 }
1457 else
1458 {
1459 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1460 }
1461 for(i=0;i<cheight;i++)
1462 {
1463 dest=addr+i*nbcols;
1464 for(j=0;j<8;j++)
1465 {
1466 mask=0x80>>j;
1467 outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
1468 readx_byte(0xa000,dest);
1469 if(fdata[src+i]&mask)
1470 {
1471 write_byte(0xa000,dest,attr&0x0f);
1472 }
1473 else
1474 {
1475 write_byte(0xa000,dest,0x00);
1476 }
1477 }
1478 }
1479 outw(VGAREG_GRDC_ADDRESS, 0xff08);
1480 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1481 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1482}
1483
1484// --------------------------------------------------------------------------------------------
1485static void write_gfx_char_cga(uint8_t car, uint8_t attr, uint8_t xcurs,
1486 uint8_t ycurs, uint8_t nbcols, uint8_t bpp)
1487{
1488 uint8_t i,j,mask,data;
1489 uint8_t *fdata;
1490 uint16_t addr,dest,src;
1491
1492 fdata = &vgafont8;
1493 addr=(xcurs*bpp)+ycurs*320;
1494 src = car * 8;
1495 for(i=0;i<8;i++)
1496 {
1497 dest=addr+(i>>1)*80;
1498 if (i & 1) dest += 0x2000;
1499 mask = 0x80;
1500 /* NB: In 1bpp modes, the attribute is ignored, only the XOR flag has meaning. */
1501 if (bpp == 1)
1502 {
1503 if (attr & 0x80)
1504 {
1505 data = read_byte(0xb800,dest);
1506 data ^= fdata[src+i];
1507 }
1508 else
1509 {
1510 data = fdata[src+i];
1511 }
1512 write_byte(0xb800,dest,data);
1513 }
1514 else
1515 {
1516 while (mask > 0)
1517 {
1518 if (attr & 0x80)
1519 {
1520 data = read_byte(0xb800,dest);
1521 }
1522 else
1523 {
1524 data = 0x00;
1525 }
1526 for(j=0;j<4;j++)
1527 {
1528 if (fdata[src+i] & mask)
1529 {
1530 if (attr & 0x80)
1531 {
1532 data ^= (attr & 0x03) << ((3-j)*2);
1533 }
1534 else
1535 {
1536 data |= (attr & 0x03) << ((3-j)*2);
1537 }
1538 }
1539 mask >>= 1;
1540 }
1541 write_byte(0xb800,dest,data);
1542 dest += 1;
1543 }
1544 }
1545 }
1546}
1547
1548// --------------------------------------------------------------------------------------------
1549static void write_gfx_char_lin(uint8_t car, uint8_t attr, uint8_t xcurs,
1550 uint8_t ycurs, uint8_t nbcols)
1551{
1552 uint8_t i,j,mask,data;
1553 uint8_t *fdata;
1554 uint16_t addr,dest,src;
1555
1556 fdata = &vgafont8;
1557 addr=xcurs*8+ycurs*nbcols*64;
1558 src = car * 8;
1559 for(i=0;i<8;i++)
1560 {
1561 dest=addr+i*nbcols*8;
1562 mask = 0x80;
1563 for(j=0;j<8;j++)
1564 {
1565 data = 0x00;
1566 if (fdata[src+i] & mask)
1567 {
1568 data = attr;
1569 }
1570 write_byte(0xa000,dest+j,data);
1571 mask >>= 1;
1572 }
1573 }
1574}
1575
1576// --------------------------------------------------------------------------------------------
1577static void biosfn_write_char_attr(uint8_t car, uint8_t page, uint8_t attr, uint16_t count)
1578{
1579 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1580 uint16_t nbcols,nbrows,address;
1581 uint16_t cursor,dummy;
1582
1583 // Get the mode
1584 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1585 line=find_vga_entry(mode);
1586 if(line==0xFF)return;
1587
1588 // Get the cursor pos for the page
1589 vga_get_cursor_pos(page,&dummy,&cursor);
1590 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1591
1592 // Get the dimensions
1593 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1594 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1595
1596 if(vga_modes[line].class==TEXT)
1597 {
1598 // Compute the address
1599 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1600
1601 dummy=((uint16_t)attr<<8)+car;
1602 memsetw(vga_modes[line].sstart,address,dummy,count);
1603 }
1604 else
1605 {
1606 // FIXME gfx mode not complete
1607 cheight=video_param_table[line_to_vpti[line]].cheight;
1608 bpp=vga_modes[line].pixbits;
1609 while(count-->0)
1610 {
1611 switch(vga_modes[line].memmodel)
1612 {
1613 case PLANAR1:
1614 attr |= 0x01; /* Color is ignored in 1bpp modes, always foreground. */
1615 case PLANAR4:
1616 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight,page);
1617 break;
1618 case CGA:
1619 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1620 break;
1621 case LINEAR8:
1622 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1623 break;
1624#ifdef VGA_DEBUG
1625 default:
1626 unimplemented();
1627#endif
1628 }
1629 xcurs++;
1630 }
1631 }
1632}
1633
1634// --------------------------------------------------------------------------------------------
1635static void biosfn_write_char_only(uint8_t car, uint8_t page, uint8_t attr, uint16_t count)
1636{
1637 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1638 uint16_t nbcols,nbrows,address;
1639 uint16_t cursor,dummy;
1640
1641 // Get the mode
1642 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1643 line=find_vga_entry(mode);
1644 if(line==0xFF)return;
1645
1646 // Get the cursor pos for the page
1647 vga_get_cursor_pos(page,&dummy,&cursor);
1648 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1649
1650 // Get the dimensions
1651 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1652 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1653
1654 if(vga_modes[line].class==TEXT)
1655 {
1656 // Compute the address
1657 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1658
1659 while(count-->0)
1660 {write_byte(vga_modes[line].sstart,address,car);
1661 address+=2;
1662 }
1663 }
1664 else
1665 {
1666 // FIXME gfx mode not complete
1667 cheight=video_param_table[line_to_vpti[line]].cheight;
1668 bpp=vga_modes[line].pixbits;
1669 while(count-->0)
1670 {
1671 switch(vga_modes[line].memmodel)
1672 {
1673 case PLANAR1:
1674 attr |= 0x01; /* Color is ignored in 1bpp modes, always foreground. */
1675 case PLANAR4:
1676 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight,page);
1677 break;
1678 case CGA:
1679 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1680 break;
1681 case LINEAR8:
1682 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1683 break;
1684#ifdef VGA_DEBUG
1685 default:
1686 unimplemented();
1687#endif
1688 }
1689 xcurs++;
1690 }
1691 }
1692}
1693
1694// --------------------------------------------------------------------------------------------
1695static void biosfn_write_pixel(uint8_t BH, uint8_t AL, uint16_t CX, uint16_t DX)
1696{
1697 uint8_t mode,line,mask,attr,data;
1698 uint16_t addr;
1699
1700 // Get the mode
1701 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1702 line=find_vga_entry(mode);
1703 if(line==0xFF)return;
1704 if(vga_modes[line].class==TEXT)return;
1705
1706 switch(vga_modes[line].memmodel)
1707 {
1708 case PLANAR4:
1709 case PLANAR1:
1710 addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1711 addr += read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE) * BH;
1712 mask = 0x80 >> (CX & 0x07);
1713 outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
1714 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1715 data = readx_byte(0xa000,addr);
1716 if (AL & 0x80)
1717 {
1718 outw(VGAREG_GRDC_ADDRESS, 0x1803);
1719 }
1720 write_byte(0xa000,addr,AL);
1721 outw(VGAREG_GRDC_ADDRESS, 0xff08);
1722 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1723 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1724 break;
1725 case CGA:
1726 if(vga_modes[line].pixbits==2)
1727 {
1728 addr=(CX>>2)+(DX>>1)*80;
1729 }
1730 else
1731 {
1732 addr=(CX>>3)+(DX>>1)*80;
1733 }
1734 if (DX & 1) addr += 0x2000;
1735 data = read_byte(0xb800,addr);
1736 if(vga_modes[line].pixbits==2)
1737 {
1738 attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
1739 mask = 0x03 << ((3 - (CX & 0x03)) * 2);
1740 }
1741 else
1742 {
1743 attr = (AL & 0x01) << (7 - (CX & 0x07));
1744 mask = 0x01 << (7 - (CX & 0x07));
1745 }
1746 if (AL & 0x80)
1747 {
1748 data ^= attr;
1749 }
1750 else
1751 {
1752 data &= ~mask;
1753 data |= attr;
1754 }
1755 write_byte(0xb800,addr,data);
1756 break;
1757 case LINEAR8:
1758 addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
1759 write_byte(0xa000,addr,AL);
1760 break;
1761#ifdef VGA_DEBUG
1762 default:
1763 unimplemented();
1764#endif
1765 }
1766}
1767
1768// --------------------------------------------------------------------------------------------
1769static void biosfn_write_teletype(uint8_t car, uint8_t page, uint8_t attr, uint8_t flag)
1770{// flag = WITH_ATTR / NO_ATTR
1771
1772 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1773 uint16_t nbcols,nbrows,address;
1774 uint16_t cursor,dummy;
1775
1776 // special case if page is 0xff, use current page
1777 if(page==0xff)
1778 page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
1779
1780 // Get the mode
1781 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1782 line=find_vga_entry(mode);
1783 if(line==0xFF)return;
1784
1785 // Get the cursor pos for the page
1786 vga_get_cursor_pos(page,&dummy,&cursor);
1787 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1788
1789 // Get the dimensions
1790 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1791 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1792
1793 switch(car)
1794 {
1795 case '\a': // ASCII 0x07, BEL
1796 //FIXME should beep
1797 break;
1798
1799 case '\b': // ASCII 0x08, BS
1800 if(xcurs>0)xcurs--;
1801 break;
1802
1803 case '\n': // ASCII 0x0A, LF
1804 ycurs++;
1805 break;
1806
1807 case '\r': // ASCII 0x0D, CR
1808 xcurs=0;
1809 break;
1810
1811 default:
1812
1813 if(vga_modes[line].class==TEXT)
1814 {
1815 // Compute the address
1816 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1817
1818 // Write the char
1819 write_byte(vga_modes[line].sstart,address,car);
1820
1821 if(flag==WITH_ATTR)
1822 write_byte(vga_modes[line].sstart,address+1,attr);
1823 }
1824 else
1825 {
1826 // FIXME gfx mode not complete
1827 cheight=video_param_table[line_to_vpti[line]].cheight;
1828 bpp=vga_modes[line].pixbits;
1829 switch(vga_modes[line].memmodel)
1830 {
1831 case PLANAR1:
1832 attr |= 0x01; /* Color is ignored in 1bpp modes, always foreground. */
1833 case PLANAR4:
1834 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight,page);
1835 break;
1836 case CGA:
1837 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1838 break;
1839 case LINEAR8:
1840 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1841 break;
1842#ifdef VGA_DEBUG
1843 default:
1844 unimplemented();
1845#endif
1846 }
1847 }
1848 xcurs++;
1849 // Do we need to wrap ?
1850 if(xcurs==nbcols)
1851 {xcurs=0;
1852 ycurs++;
1853 }
1854 }
1855
1856 // Do we need to scroll ?
1857 if(ycurs==nbrows)
1858 {
1859 if(vga_modes[line].class==TEXT)
1860 {
1861 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
1862 attr=read_byte(vga_modes[line].sstart,address+1);
1863 biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1864 }
1865 else
1866 {
1867 biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1868 }
1869 ycurs-=1;
1870 }
1871
1872 // Set the cursor for the page
1873 cursor=ycurs; cursor<<=8; cursor+=xcurs;
1874 biosfn_set_cursor_pos(page,cursor);
1875}
1876
1877// --------------------------------------------------------------------------------------------
1878static void get_font_access(void)
1879{
1880 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1881 outw(VGAREG_SEQU_ADDRESS, 0x0402);
1882 outw(VGAREG_SEQU_ADDRESS, 0x0704);
1883 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1884 outw(VGAREG_GRDC_ADDRESS, 0x0204);
1885 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1886 outw(VGAREG_GRDC_ADDRESS, 0x0406);
1887}
1888
1889static void release_font_access(void)
1890{
1891 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1892 outw(VGAREG_SEQU_ADDRESS, 0x0302);
1893 outw(VGAREG_SEQU_ADDRESS, 0x0304);
1894 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1895 outw(VGAREG_GRDC_ADDRESS, (((0x0a | ((inb(VGAREG_READ_MISC_OUTPUT) & 0x01) << 2)) << 8) | 0x06));
1896 outw(VGAREG_GRDC_ADDRESS, 0x0004);
1897 outw(VGAREG_GRDC_ADDRESS, 0x1005);
1898}
1899
1900static void set_scan_lines(uint8_t lines)
1901{
1902 uint16_t crtc_addr,cols,vde;
1903 uint8_t crtc_r9,ovl,rows;
1904
1905 crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
1906 outb(crtc_addr, 0x09);
1907 crtc_r9 = inb(crtc_addr+1);
1908 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
1909 outb(crtc_addr+1, crtc_r9);
1910 if(lines==8)
1911 {
1912 biosfn_set_cursor_shape(0x06,0x07);
1913 }
1914 else
1915 {
1916 biosfn_set_cursor_shape(lines-4,lines-3);
1917 }
1918 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
1919 outb(crtc_addr, 0x12);
1920 vde = inb(crtc_addr+1);
1921 outb(crtc_addr, 0x07);
1922 ovl = inb(crtc_addr+1);
1923 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
1924 rows = vde / lines;
1925 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
1926 cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1927 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
1928}
1929
1930static void biosfn_set_font_block(uint8_t BL)
1931{
1932 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1933 outw(VGAREG_SEQU_ADDRESS, 0x0003 | (BL << 8));
1934 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1935}
1936
1937static void biosfn_load_text_user_pat(uint8_t AL, uint16_t ES, uint16_t BP, uint16_t CX,
1938 uint16_t DX, uint8_t BL, uint8_t BH)
1939{
1940 uint16_t blockaddr,dest,i,src;
1941
1942 get_font_access();
1943 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1944 for(i=0;i<CX;i++)
1945 {
1946 src = BP + i * BH;
1947 dest = blockaddr + (DX + i) * 32;
1948 memcpyb(0xA000, dest, ES, src, BH);
1949 }
1950 release_font_access();
1951 if(AL>=0x10)
1952 {
1953 set_scan_lines(BH);
1954 }
1955}
1956
1957static void biosfn_load_text_8_14_pat(uint8_t AL, uint8_t BL)
1958{
1959 uint16_t blockaddr,dest,i,src;
1960
1961 get_font_access();
1962 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1963 for(i=0;i<0x100;i++)
1964 {
1965 src = i * 14;
1966 dest = blockaddr + i * 32;
1967 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont14+src, 14);
1968 }
1969 release_font_access();
1970 if(AL>=0x10)
1971 {
1972 set_scan_lines(14);
1973 }
1974}
1975
1976static void biosfn_load_text_8_8_pat(uint8_t AL, uint8_t BL)
1977{
1978 uint16_t blockaddr,dest,i,src;
1979
1980 get_font_access();
1981 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1982 for(i=0;i<0x100;i++)
1983 {
1984 src = i * 8;
1985 dest = blockaddr + i * 32;
1986 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont8+src, 8);
1987 }
1988 release_font_access();
1989 if(AL>=0x10)
1990 {
1991 set_scan_lines(8);
1992 }
1993}
1994
1995// --------------------------------------------------------------------------------------------
1996static void biosfn_load_text_8_16_pat(uint8_t AL, uint8_t BL)
1997{
1998 uint16_t blockaddr,dest,i,src;
1999
2000 get_font_access();
2001 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
2002 for(i=0;i<0x100;i++)
2003 {
2004 src = i * 16;
2005 dest = blockaddr + i * 32;
2006 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont16+src, 16);
2007 }
2008 release_font_access();
2009 if(AL>=0x10)
2010 {
2011 set_scan_lines(16);
2012 }
2013}
2014
2015static void biosfn_load_gfx_8_8_chars(uint16_t ES, uint16_t BP)
2016{
2017 set_int_vector(0x1F, ES:>BP);
2018}
2019
2020static void set_gfx_font(void _far *font, uint16_t cheight, uint8_t row_code, uint8_t rows)
2021{
2022 static uint8_t row_tbl[] = { 0, 14, 25, 43 };
2023
2024 set_int_vector(0x43, font);
2025 if (row_code) {
2026 if (row_code > 3)
2027 row_code = 2; /* Default to 25 rows. */
2028 rows = row_tbl[row_code];
2029 }
2030 /* Else 'rows' used as is. */
2031
2032 write_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT, cheight);
2033 write_word(BIOSMEM_SEG, BIOSMEM_NB_ROWS, rows - 1);
2034}
2035
2036static void biosfn_load_gfx_user_chars(uint16_t ES, uint16_t BP, uint16_t CX,
2037 uint8_t BL, uint8_t DL)
2038{
2039 set_gfx_font(ES:>BP, CX, BL, DL);
2040}
2041
2042/* Some references (RBIL) suggest that only BL is used; that is wrong,
2043 * all of these subfunctions will use DL if BL is zero.
2044 */
2045static void biosfn_load_gfx_8_14_chars(uint8_t BL, uint8_t DL)
2046{
2047 set_gfx_font(vgafont14, 14, BL, DL);
2048}
2049static void biosfn_load_gfx_8_8_dd_chars(uint8_t BL, uint8_t DL)
2050{
2051 set_gfx_font(vgafont8, 8, BL, DL);
2052}
2053static void biosfn_load_gfx_8_16_chars(uint8_t BL, uint8_t DL)
2054{
2055 set_gfx_font(vgafont16, 16, BL, DL);
2056}
2057// --------------------------------------------------------------------------------------------
2058static void biosfn_alternate_prtsc(void)
2059{
2060#ifdef VGA_DEBUG
2061 unimplemented();
2062#endif
2063}
2064
2065// --------------------------------------------------------------------------------------------
2066static void biosfn_switch_video_interface (AL,ES,DX) uint8_t AL;uint16_t ES;uint16_t DX;
2067{
2068#ifdef VGA_DEBUG
2069 unimplemented();
2070#endif
2071}
2072static void biosfn_enable_video_refresh_control(uint8_t AL)
2073{
2074#ifdef VGA_DEBUG
2075 unimplemented();
2076#endif
2077}
2078
2079// --------------------------------------------------------------------------------------------
2080static void biosfn_write_string(uint8_t flag, uint8_t page, uint8_t attr, uint16_t count,
2081 uint8_t row, uint8_t col, uint16_t seg, uint16_t offset)
2082{
2083 uint16_t newcurs,oldcurs,dummy;
2084 uint8_t car;
2085
2086 // Read curs info for the page
2087 vga_get_cursor_pos(page,&dummy,&oldcurs);
2088
2089 // if row=0xff special case : use current cursor position
2090 if(row==0xff)
2091 {col=oldcurs&0x00ff;
2092 row=(oldcurs&0xff00)>>8;
2093 }
2094
2095 newcurs=row; newcurs<<=8; newcurs+=col;
2096 biosfn_set_cursor_pos(page,newcurs);
2097
2098 while(count--!=0)
2099 {
2100 car=read_byte(seg,offset++);
2101 if((flag&0x02)!=0)
2102 attr=read_byte(seg,offset++);
2103
2104 biosfn_write_teletype(car,page,attr,WITH_ATTR);
2105 }
2106
2107 // Set back curs pos
2108 if((flag&0x01)==0)
2109 biosfn_set_cursor_pos(page,oldcurs);
2110}
2111
2112// --------------------------------------------------------------------------------------------
2113static void biosfn_read_state_info(uint16_t BX, uint16_t ES, uint16_t DI)
2114{
2115 uint16_t pg_sz;
2116 uint16_t scans;
2117 uint8_t mode;
2118 uint8_t mctl;
2119 uint8_t temp;
2120
2121 mode = read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
2122 pg_sz = read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE);
2123 // Address of static functionality table
2124 write_dword(ES,DI+0x00, (uint32_t)(void __far *)static_functionality);
2125
2126 // A lot is a straight copy from the BDA. Note that the number
2127 // of character rows in the BDA is zero-based but one-based in
2128 // the dynamic state area
2129 memcpyb(ES,DI+0x04,BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,30);
2130 write_byte(ES,DI+0x22,read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1);
2131 memcpyb(ES,DI+0x23,BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,2);
2132
2133 write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
2134 write_byte(ES,DI+0x26,0); // Alternate display code
2135 write_word(ES,DI+0x27,16); // Number of colors
2136 write_byte(ES,DI+0x29,8); // Number of pages
2137 write_byte(ES,DI+0x2a,2); // Vertical resolution specifier
2138 write_byte(ES,DI+0x2b,0); // Primary font block
2139 write_byte(ES,DI+0x2c,0); // Secondary font block
2140 write_byte(ES,DI+0x2d,0x21);
2141 write_byte(ES,DI+0x31,3); // 256K video RAM
2142 write_byte(ES,DI+0x32,0); // Save pointer state information
2143
2144 mctl = read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
2145
2146 /* Extract and write the vertical resolution specifier bits. */
2147 scans = ((mctl & 0x80) >> 6) | ((mctl & 0x10) >> 4);
2148 switch (scans) {
2149 case 0: temp = 1; break; /* 350 lines */
2150 case 1: temp = 2; break; /* 400 lines */
2151 default:
2152 case 2: temp = 0; break; /* 200 lines */
2153 }
2154 write_byte(ES,DI+0x2a,temp);
2155
2156 /* Patch up the data for graphics modes. */
2157 if (mode >= 0x0E && mode <= 0x12) {
2158 if (pg_sz)
2159 write_byte(ES,DI+0x29,16384/(pg_sz >> 2));
2160 } else if (mode == 0x13) {
2161 write_byte(ES,DI+0x29,1); /* Just one page due to chaining */
2162 write_word(ES,DI+0x27,256); /* But 256!! colors!!! */
2163 } else if (mode >= 4 && mode <= 6) {
2164 /* CGA modes. */
2165 if (pg_sz)
2166 write_byte(ES,DI+0x29,16384/pg_sz);
2167 write_word(ES,DI+0x27,4);
2168 }
2169 if (mode == 6 || mode == 0x11)
2170 write_word(ES,DI+0x27,2); /* 2-color modes. */
2171
2172 if ((mode >= 4) && (mode != 7)) {
2173 write_byte(ES,DI+0x2d,0x01);
2174 scans = (read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1) * read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
2175 switch (scans) {
2176 case 200: temp = 0; break;
2177 case 350: temp = 1; break;
2178 case 400: temp = 2; break;
2179 default:
2180 case 480: temp = 3; break;
2181 }
2182 write_byte(ES,DI+0x2a,temp);
2183 }
2184
2185 memsetb(ES,DI+0x33,0,13);
2186}
2187
2188// --------------------------------------------------------------------------------------------
2189uint16_t biosfn_read_video_state_size2(uint16_t state)
2190{
2191 uint16_t size;
2192
2193 size = 0;
2194 if (state & 1)
2195 size += 0x46;
2196
2197 if (state & 2)
2198 size += (5 + 8 + 5) * 2 + 6;
2199
2200 if (state & 4)
2201 size += 3 + 256 * 3 + 1;
2202
2203 return size;
2204}
2205
2206static void vga_get_video_state_size(uint16_t state, uint16_t STACK_BASED *size)
2207{
2208 /* The size is the number of 64-byte blocks required to save the state. */
2209 *size = (biosfn_read_video_state_size2(state) + 63) / 64;
2210}
2211
2212uint16_t biosfn_save_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
2213{
2214 uint16_t i, crtc_addr, ar_index;
2215
2216 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
2217 if (CX & 1) {
2218 write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
2219 write_byte(ES, BX, inb(crtc_addr)); BX++;
2220 write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
2221 inb(VGAREG_ACTL_RESET);
2222 ar_index = inb(VGAREG_ACTL_ADDRESS);
2223 write_byte(ES, BX, ar_index); BX++;
2224 write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
2225
2226 for(i=1;i<=4;i++){
2227 outb(VGAREG_SEQU_ADDRESS, i);
2228 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
2229 }
2230 outb(VGAREG_SEQU_ADDRESS, 0);
2231 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
2232
2233 for(i=0;i<=0x18;i++) {
2234 outb(crtc_addr,i);
2235 write_byte(ES, BX, inb(crtc_addr+1)); BX++;
2236 }
2237
2238 for(i=0;i<=0x13;i++) {
2239 inb(VGAREG_ACTL_RESET); /* Reads do not toggle flip-flop! */
2240 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
2241 write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
2242 }
2243 inb(VGAREG_ACTL_RESET);
2244
2245 for(i=0;i<=8;i++) {
2246 outb(VGAREG_GRDC_ADDRESS,i);
2247 write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
2248 }
2249
2250 write_word(ES, BX, crtc_addr); BX+= 2;
2251
2252 /* XXX: read plane latches */
2253 write_byte(ES, BX, 0); BX++;
2254 write_byte(ES, BX, 0); BX++;
2255 write_byte(ES, BX, 0); BX++;
2256 write_byte(ES, BX, 0); BX++;
2257 }
2258 if (CX & 2) {
2259 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
2260 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
2261 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
2262 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
2263 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
2264 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
2265 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
2266 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
2267 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
2268 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
2269 for(i=0;i<8;i++) {
2270 write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
2271 BX += 2;
2272 }
2273 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
2274 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
2275 /* current font */
2276 write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
2277 write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
2278 write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
2279 write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
2280 }
2281 if (CX & 4) {
2282 /* XXX: check this */
2283 write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
2284 write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
2285 write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
2286 // Set the whole dac always, from 0
2287 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2288 for(i=0;i<256*3;i++) {
2289 write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
2290 }
2291 write_byte(ES, BX, 0); BX++; /* color select register */
2292 }
2293 return BX;
2294}
2295
2296uint16_t biosfn_restore_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
2297{
2298 uint16_t i, crtc_addr, v, addr1, ar_index;
2299
2300 if (CX & 1) {
2301 // Reset Attribute Ctl flip-flop
2302 inb(VGAREG_ACTL_RESET);
2303
2304 crtc_addr = read_word(ES, BX + 0x40);
2305 addr1 = BX;
2306 BX += 5;
2307
2308 for(i=1;i<=4;i++){
2309 outb(VGAREG_SEQU_ADDRESS, i);
2310 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
2311 }
2312 outb(VGAREG_SEQU_ADDRESS, 0);
2313 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
2314
2315 // Disable CRTC write protection
2316 outw(crtc_addr,0x0011);
2317 // Set CRTC regs
2318 for(i=0;i<=0x18;i++) {
2319 if (i != 0x11) {
2320 outb(crtc_addr,i);
2321 outb(crtc_addr+1, read_byte(ES, BX));
2322 }
2323 BX++;
2324 }
2325 // select crtc base address
2326 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
2327 if (crtc_addr == 0x3d4)
2328 v |= 0x01;
2329 outb(VGAREG_WRITE_MISC_OUTPUT, v);
2330
2331 // enable write protection if needed
2332 outb(crtc_addr, 0x11);
2333 outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
2334
2335 // Set Attribute Ctl
2336 ar_index = read_byte(ES, addr1 + 0x03);
2337 inb(VGAREG_ACTL_RESET);
2338 for(i=0;i<=0x13;i++) {
2339 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
2340 outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
2341 }
2342 outb(VGAREG_ACTL_ADDRESS, ar_index);
2343 inb(VGAREG_ACTL_RESET);
2344
2345 for(i=0;i<=8;i++) {
2346 outb(VGAREG_GRDC_ADDRESS,i);
2347 outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
2348 }
2349 BX += 2; /* crtc_addr */
2350 BX += 4; /* plane latches */
2351
2352 outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
2353 outb(crtc_addr, read_byte(ES, addr1)); addr1++;
2354 outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
2355 addr1++;
2356 outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
2357 }
2358 if (CX & 2) {
2359 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
2360 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
2361 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
2362 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
2363 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
2364 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
2365 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
2366 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
2367 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
2368 write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
2369 for(i=0;i<8;i++) {
2370 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
2371 BX += 2;
2372 }
2373 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
2374 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
2375 /* current font */
2376 write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
2377 write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
2378 write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
2379 write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
2380 }
2381 if (CX & 4) {
2382 BX++;
2383 v = read_byte(ES, BX); BX++;
2384 outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
2385 // Set the whole dac always, from 0
2386 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2387 for(i=0;i<256*3;i++) {
2388 outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
2389 }
2390 BX++;
2391 outb(VGAREG_DAC_WRITE_ADDRESS, v);
2392 }
2393 return BX;
2394}
2395
2396// ============================================================================================
2397//
2398// Video Utils
2399//
2400// ============================================================================================
2401
2402// --------------------------------------------------------------------------------------------
2403static uint8_t find_vga_entry(uint8_t mode)
2404{
2405 uint8_t i,line=0xFF;
2406 for(i=0;i<=MODE_MAX;i++)
2407 if(vga_modes[i].svgamode==mode)
2408 {line=i;
2409 break;
2410 }
2411 return line;
2412}
2413
2414/* =========================================================== */
2415/*
2416 * Misc Utils
2417*/
2418/* =========================================================== */
2419
2420/* This function is used for planar VGA memory reads to defeat the
2421 * optimizer. We must read exactly one byte, otherwise the screen
2422 * may be corrupted.
2423 */
2424uint8_t readx_byte(uint16_t seg, uint16_t offset)
2425{
2426 return( *(seg:>(uint8_t *)offset) );
2427}
2428
2429#ifdef VGA_DEBUG
2430void __cdecl unimplemented()
2431{
2432 printf("--> Unimplemented\n");
2433}
2434
2435void __cdecl unknown()
2436{
2437 printf("--> Unknown int10\n");
2438}
2439
2440#undef VBE_PRINTF_PORT
2441#define VBE_PRINTF_PORT 0x504
2442
2443// --------------------------------------------------------------------------------------------
2444void __cdecl printf(char *s, ...)
2445{
2446 char c;
2447 Boolean in_format;
2448 unsigned format_width, i;
2449 uint16_t arg, digit, nibble;
2450 uint16_t STACK_BASED *arg_ptr;
2451
2452 arg_ptr = (uint16_t STACK_BASED *)&s;
2453
2454 in_format = 0;
2455 format_width = 0;
2456
2457 while (c = *s) {
2458 if (c == '%') {
2459 in_format = 1;
2460 format_width = 0;
2461 } else if (in_format) {
2462 if ((c >= '0') && (c <= '9')) {
2463 format_width = (format_width * 10) + (c - '0');
2464 } else if (c == 'x') {
2465 arg_ptr++; // increment to next arg
2466 arg = *arg_ptr;
2467 if (format_width == 0)
2468 format_width = 4;
2469 i = 0;
2470 digit = format_width - 1;
2471 for (i = 0; i < format_width; i++) {
2472 nibble = (arg >> (4 * digit)) & 0x000f;
2473 if (nibble <= 9)
2474 outb(VBE_PRINTF_PORT, nibble + '0');
2475 else
2476 outb(VBE_PRINTF_PORT, (nibble - 10) + 'A');
2477 digit--;
2478 }
2479 in_format = 0;
2480 }
2481 //else if (c == 'd') {
2482 // in_format = 0;
2483 // }
2484 } else {
2485 outb(VBE_PRINTF_PORT, c);
2486 }
2487 ++s;
2488 }
2489}
2490#endif
2491
2492/// @todo rearrange, call only from VBE module?
2493extern void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI);
2494extern void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI);
2495extern void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI);
2496extern 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);
2497extern 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);
2498extern 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);
2499
2500
2501// --------------------------------------------------------------------------------------------
2502/*
2503 * int10 main dispatcher
2504 */
2505void __cdecl int10_func(uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP, uint16_t BX,
2506 uint16_t DX, uint16_t CX, uint16_t AX, uint16_t DS, uint16_t ES, uint16_t FLAGS)
2507{
2508
2509 // BIOS functions
2510 switch(GET_AH())
2511 {
2512 case 0x00:
2513 biosfn_set_video_mode(GET_AL());
2514 switch(GET_AL()&0x7F)
2515 {case 6:
2516 SET_AL(0x3F);
2517 break;
2518 case 0:
2519 case 1:
2520 case 2:
2521 case 3:
2522 case 4:
2523 case 5:
2524 case 7:
2525 SET_AL(0x30);
2526 break;
2527 default:
2528 SET_AL(0x20);
2529 }
2530 break;
2531 case 0x01:
2532 biosfn_set_cursor_shape(GET_CH(),GET_CL());
2533 break;
2534 case 0x02:
2535 biosfn_set_cursor_pos(GET_BH(),DX);
2536 break;
2537 case 0x03:
2538 vga_get_cursor_pos(GET_BH(), &CX, &DX);
2539 break;
2540 case 0x04:
2541 // Read light pen pos (unimplemented)
2542#ifdef VGA_DEBUG
2543 unimplemented();
2544#endif
2545 AX=0x00;
2546 BX=0x00;
2547 CX=0x00;
2548 DX=0x00;
2549 break;
2550 case 0x05:
2551 biosfn_set_active_page(GET_AL());
2552 break;
2553 case 0x06:
2554 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
2555 break;
2556 case 0x07:
2557 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
2558 break;
2559 case 0x08:
2560 vga_read_char_attr(GET_BH(), &AX);
2561 break;
2562 case 0x09:
2563 biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
2564 break;
2565 case 0x0A:
2566 biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
2567 break;
2568 case 0x0C:
2569 biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
2570 break;
2571 case 0x0D:
2572 vga_read_pixel(GET_BH(), CX, DX, &AX);
2573 break;
2574 case 0x0E:
2575 // Ralf Brown Interrupt list is WRONG on bh(page)
2576 // We do output only on the current page !
2577#ifdef VGA_DEBUG
2578 printf("write_teletype %02x\n", GET_AL());
2579#endif
2580
2581 biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
2582 break;
2583 case 0x10:
2584 // All other functions of group AH=0x10 rewritten in assembler
2585 biosfn_perform_gray_scale_summing(BX,CX);
2586 break;
2587 case 0x11:
2588 switch(GET_AL())
2589 {
2590 case 0x00:
2591 case 0x10:
2592 biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
2593 break;
2594 case 0x01:
2595 case 0x11:
2596 biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
2597 break;
2598 case 0x02:
2599 case 0x12:
2600 biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
2601 break;
2602 case 0x03:
2603 biosfn_set_font_block(GET_BL());
2604 break;
2605 case 0x04:
2606 case 0x14:
2607 biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
2608 break;
2609 case 0x20:
2610 biosfn_load_gfx_8_8_chars(ES,BP);
2611 break;
2612 case 0x21:
2613 biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
2614 break;
2615 case 0x22:
2616 biosfn_load_gfx_8_14_chars(GET_BL(),GET_DL());
2617 break;
2618 case 0x23:
2619 biosfn_load_gfx_8_8_dd_chars(GET_BL(),GET_DL());
2620 break;
2621 case 0x24:
2622 biosfn_load_gfx_8_16_chars(GET_BL(),GET_DL());
2623 break;
2624 case 0x30:
2625 vga_get_font_info(GET_BH(), &ES, &BP, &CX, &DX);
2626 break;
2627#ifdef VGA_DEBUG
2628 default:
2629 unknown();
2630#endif
2631 }
2632
2633 break;
2634 case 0x12:
2635 switch(GET_BL())
2636 {
2637 case 0x20:
2638 biosfn_alternate_prtsc();
2639 break;
2640 case 0x34: /* CGA text cursor emulation control. */
2641 if (GET_AL() < 2) {
2642 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,
2643 (read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & ~1) | GET_AL());
2644 SET_AL(0x12);
2645 }
2646 else
2647 SET_AL(0); /* Invalid argument. */
2648 break;
2649 case 0x35:
2650 biosfn_switch_video_interface(GET_AL(),ES,DX);
2651 SET_AL(0x12);
2652 break;
2653 case 0x36:
2654 biosfn_enable_video_refresh_control(GET_AL());
2655 SET_AL(0x12);
2656 break;
2657#ifdef VGA_DEBUG
2658 default:
2659 unknown();
2660#endif
2661 }
2662 break;
2663 case 0x13:
2664 biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
2665 break;
2666 case 0x1B:
2667 biosfn_read_state_info(BX,ES,DI);
2668 SET_AL(0x1B);
2669 break;
2670 case 0x1C:
2671 switch(GET_AL())
2672 {
2673 case 0x00:
2674 vga_get_video_state_size(CX,&BX);
2675 break;
2676 case 0x01:
2677 biosfn_save_video_state(CX,ES,BX);
2678 break;
2679 case 0x02:
2680 biosfn_restore_video_state(CX,ES,BX);
2681 break;
2682#ifdef VGA_DEBUG
2683 default:
2684 unknown();
2685#endif
2686 }
2687 SET_AL(0x1C);
2688 break;
2689
2690#ifdef VBE
2691 case 0x4f:
2692 if (vbe_has_vbe_display()) {
2693 switch(GET_AL())
2694 {
2695 case 0x00:
2696 vbe_biosfn_return_controller_information(&AX,ES,DI);
2697 break;
2698 case 0x01:
2699 vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
2700 break;
2701 case 0x02:
2702 vbe_biosfn_set_mode(&AX,BX,ES,DI);
2703 break;
2704 case 0x04:
2705 vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
2706 break;
2707 case 0x06:
2708 vbe_biosfn_get_set_scanline_length(&AX, &BX, &CX, &DX);
2709 break;
2710 case 0x09:
2711 //FIXME
2712#ifdef VGA_DEBUG
2713 unimplemented();
2714#endif
2715 // function failed
2716 AX=0x100;
2717 break;
2718 case 0x0A:
2719 //FIXME
2720#ifdef VGA_DEBUG
2721 unimplemented();
2722#endif
2723 // function failed
2724 AX=0x100;
2725 break;
2726 default:
2727#ifdef VGA_DEBUG
2728 unknown();
2729#endif
2730 // function failed
2731 AX=0x100;
2732 }
2733 }
2734 else {
2735 // No VBE display
2736 AX=0x0100;
2737 }
2738 break;
2739 case 0x56:
2740 if (vbe_has_vbe_display()) {
2741 switch(GET_AL())
2742 {
2743 case 0x42:
2744 private_biosfn_custom_mode(&AX,&BX,&CX,&DX);
2745 break;
2746 default:
2747 AX=0x0100;
2748 break;
2749 }
2750 } else {
2751 // No VBE display
2752 AX=0x0100;
2753 }
2754 break;
2755#endif
2756
2757#ifdef VGA_DEBUG
2758 default:
2759 unknown();
2760#endif
2761 }
2762}
2763
2764#ifdef VBE
2765//#include "vbe.c"
2766#endif
2767
2768#ifdef CIRRUS
2769#include "clext.c"
2770#endif
2771
2772// --------------------------------------------------------------------------------------------
2773
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette