VirtualBox

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

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

VGABIOS: Do not recursively invoke INT 10h C handlers to conserve stack space; also do not recursively invoke INT 10h, rather use INT 6Dh which should not be hooked (see bugref:6549).

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