VirtualBox

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

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

VGABIOS: Implemented character reads in graphics modes, fixed 1bpp graphics text output.

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

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