VirtualBox

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

最後變更 在這個檔案從93841是 93841,由 vboxsync 提交於 3 年 前

VGABIOS: Reworked save area management, added support for font overrides, enabled mono mode 7.

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

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