VirtualBox

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

Last change on this file since 83002 was 83002, checked in by vboxsync, 5 years ago

VGABIOS: Further reduced mode set stack usage, centralized cld invocation, reduced explicit C000 segment usage.

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