VirtualBox

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

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

VGABIOS: Use a real 8x16 font and apply 9x16 patches when setting mode (see bugref:6549).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use