VirtualBox

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

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

VGABIOS: Fixed CGA cursor emulation (new code is much more complex but also much more IBM compatible).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.8 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] = 0x68;
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
340static void vga_read_char_attr(uint8_t page, uint16_t STACK_BASED *chr_atr)
341{
342 uint8_t xcurs, ycurs, mode, line;
343 uint16_t nbcols, nbrows, address;
344 uint16_t cursor, dummy;
345
346 // Get the mode
347 mode = read_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE);
348 line = find_vga_entry(mode);
349 if (line == 0xFF)
350 return;
351
352 // Get the cursor pos for the page
353 vga_get_cursor_pos(page, &dummy, &cursor);
354 xcurs = cursor & 0x00ff;
355 ycurs = (cursor & 0xff00) >> 8;
356
357 // Get the dimensions
358 nbrows = read_byte(BIOSMEM_SEG, BIOSMEM_NB_ROWS) + 1;
359 nbcols = read_word(BIOSMEM_SEG, BIOSMEM_NB_COLS);
360
361 if (vga_modes[line].class == TEXT) {
362 // Compute the address
363 address = SCREEN_MEM_START(nbcols, nbrows, page) + (xcurs + ycurs * nbcols) * 2;
364 *chr_atr = read_word(vga_modes[line].sstart, address);
365 } else {
366 /// @todo graphics modes (not so easy - or useful!)
367#ifdef VGA_DEBUG
368 unimplemented();
369#endif
370 }
371}
372
373static void vga_get_font_info (uint16_t func, uint16_t STACK_BASED *u_seg, uint16_t STACK_BASED *u_ofs,
374 uint16_t STACK_BASED *c_height, uint16_t STACK_BASED *max_row)
375{
376 void __far *ptr;
377
378 switch (func) {
379 case 0x00:
380 ptr = (void __far *)read_dword(0x00, 0x1f * 4);
381 break;
382 case 0x01:
383 ptr = (void __far *)read_dword(0x00, 0x43 * 4);
384 break;
385 case 0x02:
386 ptr = 0xC000 :> vgafont14;
387 break;
388 case 0x03:
389 ptr = 0xC000 :> vgafont8;
390 break;
391 case 0x04:
392 ptr = 0xC000 :> (vgafont8 + 128 * 8);
393 break;
394 case 0x05:
395 ptr = 0xC000 :> vgafont14alt;
396 break;
397 case 0x06:
398 ptr = 0xC000 :> vgafont16;
399 break;
400 case 0x07:
401 ptr = 0xC000 :> vgafont16alt;
402 break;
403 default:
404#ifdef VGA_DEBUG
405 printf("Get font info subfn(%02x) not implemented\n", func);
406#endif
407 return;
408 }
409 /* Split the far pointer and write it back. */
410 *u_ofs = (uint16_t)ptr;
411 *u_seg = (uint32_t)ptr >> 16;
412
413 /* The character height (effectively bytes per glyph). */
414 *c_height = read_byte(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
415
416 /* The highest row number. */
417 *max_row = read_byte(BIOSMEM_SEG, BIOSMEM_NB_ROWS);
418}
419
420static void vga_read_pixel(uint8_t page, uint16_t col, uint16_t row, uint16_t STACK_BASED *pixel)
421{
422 uint8_t mode, line, mask, attr, data, i;
423 uint16_t addr;
424
425 /* Determine current mode characteristics. */
426 mode = read_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE);
427 line = find_vga_entry(mode);
428 if (line == 0xFF)
429 return;
430 if (vga_modes[line].class == TEXT)
431 return;
432
433 /* Read data depending on memory model. */
434 switch (vga_modes[line].memmodel) {
435 case PLANAR4:
436 case PLANAR1:
437 addr = col / 8 + row * read_word(BIOSMEM_SEG, BIOSMEM_NB_COLS);
438 mask = 0x80 >> (col & 0x07);
439 attr = 0x00;
440 for (i = 0; i < 4; i++) {
441 outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
442 data = read_byte(0xa000,addr) & mask;
443 if (data > 0)
444 attr |= (0x01 << i);
445 }
446 break;
447 case CGA:
448 addr = (col >> (4 - vga_modes[line].pixbits)) + (row >> 1) * 80;
449 if (row & 1)
450 addr += 0x2000;
451 data = read_byte(0xb800, addr);
452 if (vga_modes[line].pixbits == 2)
453 attr = (data >> ((3 - (col & 0x03)) * 2)) & 0x03;
454 else
455 attr = (data >> (7 - (col & 0x07))) & 0x01;
456 break;
457 case LINEAR8:
458 addr = col + row * (read_word(BIOSMEM_SEG, BIOSMEM_NB_COLS) * 8);
459 attr = read_byte(0xa000, addr);
460 break;
461 default:
462#ifdef VGA_DEBUG
463 unimplemented();
464#endif
465 attr = 0;
466 }
467 *(uint8_t STACK_BASED *)pixel = attr;
468}
469
470
471
472// --------------------------------------------------------------------------------------------
473/*static*/ void biosfn_perform_gray_scale_summing(uint16_t start, uint16_t count)
474{uint8_t r,g,b;
475 uint16_t i;
476 uint16_t index;
477
478 inb(VGAREG_ACTL_RESET);
479 outb(VGAREG_ACTL_ADDRESS,0x00);
480
481 for( index = 0; index < count; index++ )
482 {
483 // set read address and switch to read mode
484 outb(VGAREG_DAC_READ_ADDRESS,start);
485 // get 6-bit wide RGB data values
486 r=inb( VGAREG_DAC_DATA );
487 g=inb( VGAREG_DAC_DATA );
488 b=inb( VGAREG_DAC_DATA );
489
490 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
491 i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
492
493 if(i>0x3f)i=0x3f;
494
495 // set write address and switch to write mode
496 outb(VGAREG_DAC_WRITE_ADDRESS,start);
497 // write new intensity value
498 outb( VGAREG_DAC_DATA, i&0xff );
499 outb( VGAREG_DAC_DATA, i&0xff );
500 outb( VGAREG_DAC_DATA, i&0xff );
501 start++;
502 }
503 inb(VGAREG_ACTL_RESET);
504 outb(VGAREG_ACTL_ADDRESS,0x20);
505#ifdef VBOX
506 inb(VGAREG_ACTL_RESET);
507#endif /* VBOX */
508}
509
510// --------------------------------------------------------------------------------------------
511static void biosfn_set_cursor_shape(uint8_t CH, uint8_t CL)
512{
513 uint16_t cheight, curs, crtc_addr;
514 int cga_emu;
515
516 /* Unmodified input is stored in the BDA. */
517 curs = (CH << 8) + CL;
518 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_TYPE, curs);
519
520 /* Check if VGA is active. If not, just write the input to the CRTC. */
521 if (read_byte(BIOSMEM_SEG, BIOSMEM_VIDEO_CTL) & 8) {
522 /* Trying to disable the cursor? */
523 if ((CH & 0x60) == 0x20) {
524 /* Special IBM-compatible value to turn off cursor. */
525 CH = 0x1E;
526 CL = 0;
527 } else {
528 cga_emu = !(read_byte(BIOSMEM_SEG, BIOSMEM_VIDEO_CTL) & 1);
529
530 /* If CGA cursor emulation is on and this is a text mode, adjust.
531 * But if cursor star or end is bigger than 31, don't adjust.
532 */
533 // @todo: Figure out if this is a text mode
534 if (cga_emu /* && text mode*/ && (CH < 32) && (CL < 32)) {
535 cheight = read_word(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
536
537 /* Is the end lower than start? VGA does not wrap around.*/
538 if (CL < CH) {
539 /* For zero CL (end), leave values unchanged. */
540 if (CL) {
541 CH = 0;
542 CL = cheight - 1;
543 }
544 } else {
545 if (((CL | CH) >= cheight) || ((CL != cheight - 1) && (CH != cheight - 2))) {
546 /* If it's an overbar cursor, don't adjust. */
547 if (CL > 3) {
548 if (CL <= CH + 2) {
549 /* It's it a normal underline style cursor. */
550 CH = CH - CL + cheight - 1;
551 CL = cheight - 1;
552 if (cheight >= 14) {
553 /* Shift up one pixel for normal EGA/VGA fonts. */
554 CL--;
555 CH--;
556 }
557 } else if (CH <= 2) {
558 /* It's a full block cursor. */
559 CL = cheight - 1;
560 } else {
561 /* It's a half block cursor. */
562 CH = cheight / 2;
563 CL = cheight - 1;
564 }
565 }
566 }
567 }
568 }
569 }
570 }
571
572 // CTRC regs 0x0a and 0x0b
573 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
574 outb(crtc_addr, 0x0a);
575 outb(crtc_addr + 1, CH);
576 outb(crtc_addr, 0x0b);
577 outb(crtc_addr + 1 ,CL);
578}
579
580// --------------------------------------------------------------------------------------------
581static void biosfn_set_cursor_pos (uint8_t page, uint16_t cursor)
582{
583 uint8_t xcurs,ycurs,current;
584 uint16_t nbcols,nbrows,address,crtc_addr;
585
586 // Should not happen...
587 if(page>7)return;
588
589 // Bios cursor pos
590 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
591
592 // Set the hardware cursor
593 current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
594 if(page==current)
595 {
596 // Get the dimensions
597 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
598 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
599
600 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
601
602 // Calculate the address knowing nbcols nbrows and page num
603 address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
604
605 // CRTC regs 0x0e and 0x0f
606 crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
607 outb(crtc_addr,0x0e);
608 outb(crtc_addr+1,(address&0xff00)>>8);
609 outb(crtc_addr,0x0f);
610 outb(crtc_addr+1,address&0x00ff);
611 }
612}
613
614// --------------------------------------------------------------------------------------------
615static void biosfn_set_active_page(uint8_t page)
616{
617 uint16_t cursor,dummy,crtc_addr;
618 uint16_t nbcols,nbrows,address;
619 uint8_t mode,line;
620
621 if(page>7)return;
622
623 // Get the mode
624 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
625 line=find_vga_entry(mode);
626 if(line==0xFF)return;
627
628 // Get pos curs pos for the right page
629 vga_get_cursor_pos(page,&dummy,&cursor);
630
631 if(vga_modes[line].class==TEXT)
632 {
633 // Get the dimensions
634 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
635 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
636
637 // Calculate the address knowing nbcols nbrows and page num
638 address=SCREEN_MEM_START(nbcols,nbrows,page);
639 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
640
641 // Start address
642 address=SCREEN_IO_START(nbcols,nbrows,page);
643 }
644 else
645 {
646 address = page * (*(uint16_t *)&video_param_table[line_to_vpti[line]].slength_l);
647 }
648
649 // CRTC regs 0x0c and 0x0d
650 crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
651 outb(crtc_addr,0x0c);
652 outb(crtc_addr+1,(address&0xff00)>>8);
653 outb(crtc_addr,0x0d);
654 outb(crtc_addr+1,address&0x00ff);
655
656 // And change the BIOS page
657 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
658
659#ifdef VGA_DEBUG
660 printf("Set active page %02x address %04x\n",page,address);
661#endif
662
663 // Display the cursor, now the page is active
664 biosfn_set_cursor_pos(page,cursor);
665}
666
667/// @todo Evaluate whether executing INT 10h is the right thing here
668extern void vga_font_set(uint8_t function, uint8_t data);
669#pragma aux vga_font_set = \
670 "mov ah, 11h" \
671 "int 10h" \
672 parm [al] [bl];
673
674// ============================================================================================
675//
676// BIOS functions
677//
678// ============================================================================================
679
680/* CGA-compatible MSR (0x3D8) register values for first modes 0-7. */
681uint8_t cga_msr[8] = {
682 0x2C, 0x28, 0x2D, 0x29, 0x2A, 0x2E, 0x1E, 0x29
683};
684
685void biosfn_set_video_mode(uint8_t mode)
686{// mode: Bit 7 is 1 if no clear screen
687
688 // Should we clear the screen ?
689 uint8_t noclearmem=mode&0x80;
690 uint8_t line,mmask,*palette,vpti;
691 uint16_t i,twidth,theightm1,cheight;
692 uint8_t modeset_ctl,video_ctl,vga_switches;
693 uint16_t crtc_addr;
694
695#ifdef VBE
696 if (vbe_has_vbe_display()) {
697 // Force controller into VGA mode
698 outb(VGAREG_SEQU_ADDRESS,7);
699 outb(VGAREG_SEQU_DATA,0x00);
700 }
701#endif // def VBE
702
703 // The real mode
704 mode=mode&0x7f;
705
706 // Display switching is not supported, and mono monitors aren't either.
707 // Requests to set mode 7 (mono) must set mode 0 instead (color).
708 if (mode == 7)
709 mode = 0;
710
711 // find the entry in the video modes
712 line=find_vga_entry(mode);
713
714#ifdef VGA_DEBUG
715 printf("mode search %02x found line %02x\n",mode,line);
716#endif
717
718 if(line==0xFF)
719 return;
720
721 vpti=line_to_vpti[line];
722 twidth=video_param_table[vpti].twidth;
723 theightm1=video_param_table[vpti].theightm1;
724 cheight=video_param_table[vpti].cheight;
725
726 // Read the bios vga control
727 video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
728
729 // Read the bios vga switches
730 vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
731
732 // Read the bios mode set control
733 modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
734
735 // Then we know the number of lines
736// FIXME
737
738 // if palette loading (bit 3 of modeset ctl = 0)
739 if((modeset_ctl&0x08)==0)
740 {// Set the PEL mask
741 outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
742
743 // Set the whole dac always, from 0
744 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
745
746 // From which palette
747 switch(vga_modes[line].dacmodel)
748 {case 0:
749 palette=&palette0[0];
750 break;
751 case 1:
752 palette=&palette1[0];
753 break;
754 case 2:
755 palette=&palette2[0];
756 break;
757 case 3:
758 palette=&palette3[0];
759 break;
760 }
761 // Always 256*3 values
762 for(i=0;i<0x0100;i++)
763 {if(i<=dac_regs[vga_modes[line].dacmodel])
764 {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
765 outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
766 outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
767 }
768 else
769 {outb(VGAREG_DAC_DATA,0);
770 outb(VGAREG_DAC_DATA,0);
771 outb(VGAREG_DAC_DATA,0);
772 }
773 }
774 if((modeset_ctl&0x02)==0x02)
775 {
776 biosfn_perform_gray_scale_summing(0x00, 0x100);
777 }
778 }
779
780 // Reset Attribute Ctl flip-flop
781 inb(VGAREG_ACTL_RESET);
782
783 // Set Attribute Ctl
784 for(i=0;i<=0x13;i++)
785 {outb(VGAREG_ACTL_ADDRESS,i);
786 outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
787 }
788 outb(VGAREG_ACTL_ADDRESS,0x14);
789 outb(VGAREG_ACTL_WRITE_DATA,0x00);
790
791 // Set Sequencer Ctl
792 outb(VGAREG_SEQU_ADDRESS,0);
793 outb(VGAREG_SEQU_DATA,0x03);
794 for(i=1;i<=4;i++)
795 {outb(VGAREG_SEQU_ADDRESS,i);
796 outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
797 }
798
799 // Set Grafx Ctl
800 for(i=0;i<=8;i++)
801 {outb(VGAREG_GRDC_ADDRESS,i);
802 outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
803 }
804
805 // Set CRTC address VGA or MDA
806 crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
807
808 // Disable CRTC write protection
809 outw(crtc_addr,0x0011);
810 // Set CRTC regs
811 for(i=0;i<=0x18;i++)
812 {outb(crtc_addr,i);
813 outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
814 }
815
816 // Set the misc register
817 outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
818
819 // Enable video
820 outb(VGAREG_ACTL_ADDRESS,0x20);
821 inb(VGAREG_ACTL_RESET);
822
823 if(noclearmem==0x00)
824 {
825 if(vga_modes[line].class==TEXT)
826 {
827 memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
828 }
829 else
830 {
831 if(mode<0x0d)
832 {
833 memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
834 }
835 else
836 {
837 outb( VGAREG_SEQU_ADDRESS, 0x02 );
838 mmask = inb( VGAREG_SEQU_DATA );
839 outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
840 memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
841 outb( VGAREG_SEQU_DATA, mmask );
842 }
843 }
844 }
845
846 // Set the BIOS mem
847 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
848 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
849 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(uint16_t *)&video_param_table[vpti].slength_l);
850 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
851 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
852 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
853 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x68|noclearmem));
854 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
855 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
856
857 // FIXME We nearly have the good tables. to be reworked
858 write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
859 write_dword(BIOSMEM_SEG,BIOSMEM_VS_POINTER, (uint32_t)(void __far *)video_save_pointer_table);
860
861 if (mode <= 7)
862 {
863 write_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_MSR, cga_msr[mode]); /* Like CGA reg. 0x3D8 */
864 write_byte(BIOSMEM_SEG, BIOSMEM_CURRENT_PAL, mode == 6 ? 0x3F : 0x30); /* Like CGA reg. 0x3D9*/
865 }
866
867 // Set cursor shape
868 if(vga_modes[line].class==TEXT)
869 {
870 biosfn_set_cursor_shape(0x06,0x07);
871 }
872
873 // Set cursor pos for page 0..7
874 for(i=0;i<8;i++)
875 biosfn_set_cursor_pos(i,0x0000);
876
877 // Set active page 0
878 biosfn_set_active_page(0x00);
879
880 // Write the fonts in memory
881 if(vga_modes[line].class==TEXT)
882 {
883 vga_font_set(0x04, 0); /* Load 8x16 font into page 0. */
884 vga_font_set(0x03, 0); /* Select font page mode 0. */
885 }
886
887 // Set the ints 0x1F and 0x43
888 set_int_vector(0x1f, vgafont8+128*8);
889
890 switch(cheight)
891 {case 8:
892 set_int_vector(0x43, vgafont8);
893 break;
894 case 14:
895 set_int_vector(0x43, vgafont14);
896 break;
897 case 16:
898 set_int_vector(0x43, vgafont16);
899 break;
900 }
901}
902
903// --------------------------------------------------------------------------------------------
904static void vgamem_copy_pl4(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
905 uint8_t cols, uint8_t nbcols, uint8_t cheight)
906{
907 uint16_t src,dest;
908 uint8_t i;
909
910 src=ysrc*cheight*nbcols+xstart;
911 dest=ydest*cheight*nbcols+xstart;
912 outw(VGAREG_GRDC_ADDRESS, 0x0105);
913 for(i=0;i<cheight;i++)
914 {
915 memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
916 }
917 outw(VGAREG_GRDC_ADDRESS, 0x0005);
918}
919
920// --------------------------------------------------------------------------------------------
921static void vgamem_fill_pl4(uint8_t xstart, uint8_t ystart, uint8_t cols,
922 uint8_t nbcols, uint8_t cheight, uint8_t attr)
923{
924 uint16_t dest;
925 uint8_t i;
926
927 dest=ystart*cheight*nbcols+xstart;
928 outw(VGAREG_GRDC_ADDRESS, 0x0205);
929 for(i=0;i<cheight;i++)
930 {
931 memsetb(0xa000,dest+i*nbcols,attr,cols);
932 }
933 outw(VGAREG_GRDC_ADDRESS, 0x0005);
934}
935
936// --------------------------------------------------------------------------------------------
937static void vgamem_copy_cga(uint8_t xstart, uint8_t ysrc, uint8_t ydest,
938 uint8_t cols, uint8_t nbcols, uint8_t cheight)
939{
940 uint16_t src,dest;
941 uint8_t i;
942
943 src=((ysrc*cheight*nbcols)>>1)+xstart;
944 dest=((ydest*cheight*nbcols)>>1)+xstart;
945 for(i=0;i<cheight;i++)
946 {
947 if (i & 1)
948 memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
949 else
950 memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
951 }
952}
953
954// --------------------------------------------------------------------------------------------
955static void vgamem_fill_cga(uint8_t xstart, uint8_t ystart, uint8_t cols,
956 uint8_t nbcols, uint8_t cheight, uint8_t attr)
957{
958 uint16_t dest;
959 uint8_t i;
960
961 dest=((ystart*cheight*nbcols)>>1)+xstart;
962 for(i=0;i<cheight;i++)
963 {
964 if (i & 1)
965 memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
966 else
967 memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
968 }
969}
970
971// --------------------------------------------------------------------------------------------
972static void biosfn_scroll(uint8_t nblines, uint8_t attr, uint8_t rul, uint8_t cul,
973 uint8_t rlr, uint8_t clr, uint8_t page, uint8_t dir)
974{
975 // page == 0xFF if current
976
977 uint8_t mode,line,cheight,bpp,cols;
978 uint16_t nbcols,nbrows,i;
979 uint16_t address;
980
981 if(rul>rlr)return;
982 if(cul>clr)return;
983
984 // Get the mode
985 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
986 line=find_vga_entry(mode);
987 if(line==0xFF)return;
988
989 // Get the dimensions
990 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
991 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
992
993 // Get the current page
994 if(page==0xFF)
995 page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
996
997 if(rlr>=nbrows)rlr=nbrows-1;
998 if(clr>=nbcols)clr=nbcols-1;
999 if(nblines>nbrows)nblines=0;
1000 cols=clr-cul+1;
1001
1002 if(vga_modes[line].class==TEXT)
1003 {
1004 // Compute the address
1005 address=SCREEN_MEM_START(nbcols,nbrows,page);
1006#ifdef VGA_DEBUG
1007 printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
1008#endif
1009
1010 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1011 {
1012 memsetw(vga_modes[line].sstart,address,(uint16_t)attr*0x100+' ',nbrows*nbcols);
1013 }
1014 else
1015 {// if Scroll up
1016 if(dir==SCROLL_UP)
1017 {for(i=rul;i<=rlr;i++)
1018 {
1019 if((i+nblines>rlr)||(nblines==0))
1020 memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(uint16_t)attr*0x100+' ',cols);
1021 else
1022 memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
1023 }
1024 }
1025 else
1026 {for(i=rlr;i>=rul;i--)
1027 {
1028 if((i<rul+nblines)||(nblines==0))
1029 memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(uint16_t)attr*0x100+' ',cols);
1030 else
1031 memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
1032 if (i>rlr) break;
1033 }
1034 }
1035 }
1036 }
1037 else
1038 {
1039 // FIXME gfx mode not complete
1040 cheight=video_param_table[line_to_vpti[line]].cheight;
1041 switch(vga_modes[line].memmodel)
1042 {
1043 case PLANAR4:
1044 case PLANAR1:
1045 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1046 {
1047 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1048 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
1049 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1050 }
1051 else
1052 {// if Scroll up
1053 if(dir==SCROLL_UP)
1054 {for(i=rul;i<=rlr;i++)
1055 {
1056 if((i+nblines>rlr)||(nblines==0))
1057 vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
1058 else
1059 vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
1060 }
1061 }
1062 else
1063 {for(i=rlr;i>=rul;i--)
1064 {
1065 if((i<rul+nblines)||(nblines==0))
1066 vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
1067 else
1068 vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
1069 if (i>rlr) break;
1070 }
1071 }
1072 }
1073 break;
1074 case CGA:
1075 bpp=vga_modes[line].pixbits;
1076 if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
1077 {
1078 memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
1079 }
1080 else
1081 {
1082 if(bpp==2)
1083 {
1084 cul<<=1;
1085 cols<<=1;
1086 nbcols<<=1;
1087 }
1088 // if Scroll up
1089 if(dir==SCROLL_UP)
1090 {for(i=rul;i<=rlr;i++)
1091 {
1092 if((i+nblines>rlr)||(nblines==0))
1093 vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
1094 else
1095 vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
1096 }
1097 }
1098 else
1099 {for(i=rlr;i>=rul;i--)
1100 {
1101 if((i<rul+nblines)||(nblines==0))
1102 vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
1103 else
1104 vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
1105 if (i>rlr) break;
1106 }
1107 }
1108 }
1109 break;
1110#ifdef VGA_DEBUG
1111 default:
1112 printf("Scroll in graphics mode ");
1113 unimplemented();
1114#endif
1115 }
1116 }
1117}
1118
1119// --------------------------------------------------------------------------------------------
1120static void write_gfx_char_pl4(uint8_t car, uint8_t attr, uint8_t xcurs,
1121 uint8_t ycurs, uint8_t nbcols, uint8_t cheight)
1122{
1123 uint8_t i,j,mask;
1124 uint8_t *fdata;
1125 uint16_t addr,dest,src;
1126
1127 switch(cheight)
1128 {case 14:
1129 fdata = &vgafont14;
1130 break;
1131 case 16:
1132 fdata = &vgafont16;
1133 break;
1134 default:
1135 fdata = &vgafont8;
1136 }
1137 addr=xcurs+ycurs*cheight*nbcols;
1138 src = car * cheight;
1139 outw(VGAREG_SEQU_ADDRESS, 0x0f02);
1140 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1141 if(attr&0x80)
1142 {
1143 outw(VGAREG_GRDC_ADDRESS, 0x1803);
1144 }
1145 else
1146 {
1147 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1148 }
1149 for(i=0;i<cheight;i++)
1150 {
1151 dest=addr+i*nbcols;
1152 for(j=0;j<8;j++)
1153 {
1154 mask=0x80>>j;
1155 outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
1156 read_byte(0xa000,dest);
1157 if(fdata[src+i]&mask)
1158 {
1159 write_byte(0xa000,dest,attr&0x0f);
1160 }
1161 else
1162 {
1163 write_byte(0xa000,dest,0x00);
1164 }
1165 }
1166 }
1167 outw(VGAREG_GRDC_ADDRESS, 0xff08);
1168 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1169 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1170}
1171
1172// --------------------------------------------------------------------------------------------
1173static void write_gfx_char_cga(uint8_t car, uint8_t attr, uint8_t xcurs,
1174 uint8_t ycurs, uint8_t nbcols, uint8_t bpp)
1175{
1176 uint8_t i,j,mask,data;
1177 uint8_t *fdata;
1178 uint16_t addr,dest,src;
1179
1180 fdata = &vgafont8;
1181 addr=(xcurs*bpp)+ycurs*320;
1182 src = car * 8;
1183 for(i=0;i<8;i++)
1184 {
1185 dest=addr+(i>>1)*80;
1186 if (i & 1) dest += 0x2000;
1187 mask = 0x80;
1188 if (bpp == 1)
1189 {
1190 if (attr & 0x80)
1191 {
1192 data = read_byte(0xb800,dest);
1193 }
1194 else
1195 {
1196 data = 0x00;
1197 }
1198 for(j=0;j<8;j++)
1199 {
1200 if (fdata[src+i] & mask)
1201 {
1202 if (attr & 0x80)
1203 {
1204 data ^= (attr & 0x01) << (7-j);
1205 }
1206 else
1207 {
1208 data |= (attr & 0x01) << (7-j);
1209 }
1210 }
1211 mask >>= 1;
1212 }
1213 write_byte(0xb800,dest,data);
1214 }
1215 else
1216 {
1217 while (mask > 0)
1218 {
1219 if (attr & 0x80)
1220 {
1221 data = read_byte(0xb800,dest);
1222 }
1223 else
1224 {
1225 data = 0x00;
1226 }
1227 for(j=0;j<4;j++)
1228 {
1229 if (fdata[src+i] & mask)
1230 {
1231 if (attr & 0x80)
1232 {
1233 data ^= (attr & 0x03) << ((3-j)*2);
1234 }
1235 else
1236 {
1237 data |= (attr & 0x03) << ((3-j)*2);
1238 }
1239 }
1240 mask >>= 1;
1241 }
1242 write_byte(0xb800,dest,data);
1243 dest += 1;
1244 }
1245 }
1246 }
1247}
1248
1249// --------------------------------------------------------------------------------------------
1250static void write_gfx_char_lin(uint8_t car, uint8_t attr, uint8_t xcurs,
1251 uint8_t ycurs, uint8_t nbcols)
1252{
1253 uint8_t i,j,mask,data;
1254 uint8_t *fdata;
1255 uint16_t addr,dest,src;
1256
1257 fdata = &vgafont8;
1258 addr=xcurs*8+ycurs*nbcols*64;
1259 src = car * 8;
1260 for(i=0;i<8;i++)
1261 {
1262 dest=addr+i*nbcols*8;
1263 mask = 0x80;
1264 for(j=0;j<8;j++)
1265 {
1266 data = 0x00;
1267 if (fdata[src+i] & mask)
1268 {
1269 data = attr;
1270 }
1271 write_byte(0xa000,dest+j,data);
1272 mask >>= 1;
1273 }
1274 }
1275}
1276
1277// --------------------------------------------------------------------------------------------
1278static void biosfn_write_char_attr(uint8_t car, uint8_t page, uint8_t attr, uint16_t count)
1279{
1280 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1281 uint16_t nbcols,nbrows,address;
1282 uint16_t cursor,dummy;
1283
1284 // Get the mode
1285 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1286 line=find_vga_entry(mode);
1287 if(line==0xFF)return;
1288
1289 // Get the cursor pos for the page
1290 vga_get_cursor_pos(page,&dummy,&cursor);
1291 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1292
1293 // Get the dimensions
1294 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1295 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1296
1297 if(vga_modes[line].class==TEXT)
1298 {
1299 // Compute the address
1300 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1301
1302 dummy=((uint16_t)attr<<8)+car;
1303 memsetw(vga_modes[line].sstart,address,dummy,count);
1304 }
1305 else
1306 {
1307 // FIXME gfx mode not complete
1308 cheight=video_param_table[line_to_vpti[line]].cheight;
1309 bpp=vga_modes[line].pixbits;
1310 while((count-->0) && (xcurs<nbcols))
1311 {
1312 switch(vga_modes[line].memmodel)
1313 {
1314 case PLANAR4:
1315 case PLANAR1:
1316 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
1317 break;
1318 case CGA:
1319 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1320 break;
1321 case LINEAR8:
1322 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1323 break;
1324#ifdef VGA_DEBUG
1325 default:
1326 unimplemented();
1327#endif
1328 }
1329 xcurs++;
1330 }
1331 }
1332}
1333
1334// --------------------------------------------------------------------------------------------
1335static void biosfn_write_char_only(uint8_t car, uint8_t page, uint8_t attr, uint16_t count)
1336{
1337 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1338 uint16_t nbcols,nbrows,address;
1339 uint16_t cursor,dummy;
1340
1341 // Get the mode
1342 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1343 line=find_vga_entry(mode);
1344 if(line==0xFF)return;
1345
1346 // Get the cursor pos for the page
1347 vga_get_cursor_pos(page,&dummy,&cursor);
1348 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1349
1350 // Get the dimensions
1351 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1352 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1353
1354 if(vga_modes[line].class==TEXT)
1355 {
1356 // Compute the address
1357 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1358
1359 while(count-->0)
1360 {write_byte(vga_modes[line].sstart,address,car);
1361 address+=2;
1362 }
1363 }
1364 else
1365 {
1366 // FIXME gfx mode not complete
1367 cheight=video_param_table[line_to_vpti[line]].cheight;
1368 bpp=vga_modes[line].pixbits;
1369 while((count-->0) && (xcurs<nbcols))
1370 {
1371 switch(vga_modes[line].memmodel)
1372 {
1373 case PLANAR4:
1374 case PLANAR1:
1375 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
1376 break;
1377 case CGA:
1378 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1379 break;
1380 case LINEAR8:
1381 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1382 break;
1383#ifdef VGA_DEBUG
1384 default:
1385 unimplemented();
1386#endif
1387 }
1388 xcurs++;
1389 }
1390 }
1391}
1392
1393// --------------------------------------------------------------------------------------------
1394static void biosfn_write_pixel(uint8_t BH, uint8_t AL, uint16_t CX, uint16_t DX)
1395{
1396 uint8_t mode,line,mask,attr,data;
1397 uint16_t addr;
1398
1399 // Get the mode
1400 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1401 line=find_vga_entry(mode);
1402 if(line==0xFF)return;
1403 if(vga_modes[line].class==TEXT)return;
1404
1405 switch(vga_modes[line].memmodel)
1406 {
1407 case PLANAR4:
1408 case PLANAR1:
1409 addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1410 mask = 0x80 >> (CX & 0x07);
1411 outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
1412 outw(VGAREG_GRDC_ADDRESS, 0x0205);
1413 data = read_byte(0xa000,addr);
1414 if (AL & 0x80)
1415 {
1416 outw(VGAREG_GRDC_ADDRESS, 0x1803);
1417 }
1418 write_byte(0xa000,addr,AL);
1419 outw(VGAREG_GRDC_ADDRESS, 0xff08);
1420 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1421 outw(VGAREG_GRDC_ADDRESS, 0x0003);
1422 break;
1423 case CGA:
1424 if(vga_modes[line].pixbits==2)
1425 {
1426 addr=(CX>>2)+(DX>>1)*80;
1427 }
1428 else
1429 {
1430 addr=(CX>>3)+(DX>>1)*80;
1431 }
1432 if (DX & 1) addr += 0x2000;
1433 data = read_byte(0xb800,addr);
1434 if(vga_modes[line].pixbits==2)
1435 {
1436 attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
1437 mask = 0x03 << ((3 - (CX & 0x03)) * 2);
1438 }
1439 else
1440 {
1441 attr = (AL & 0x01) << (7 - (CX & 0x07));
1442 mask = 0x01 << (7 - (CX & 0x07));
1443 }
1444 if (AL & 0x80)
1445 {
1446 data ^= attr;
1447 }
1448 else
1449 {
1450 data &= ~mask;
1451 data |= attr;
1452 }
1453 write_byte(0xb800,addr,data);
1454 break;
1455 case LINEAR8:
1456 addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
1457 write_byte(0xa000,addr,AL);
1458 break;
1459#ifdef VGA_DEBUG
1460 default:
1461 unimplemented();
1462#endif
1463 }
1464}
1465
1466// --------------------------------------------------------------------------------------------
1467static void biosfn_write_teletype(uint8_t car, uint8_t page, uint8_t attr, uint8_t flag)
1468{// flag = WITH_ATTR / NO_ATTR
1469
1470 uint8_t cheight,xcurs,ycurs,mode,line,bpp;
1471 uint16_t nbcols,nbrows,address;
1472 uint16_t cursor,dummy;
1473
1474 // special case if page is 0xff, use current page
1475 if(page==0xff)
1476 page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
1477
1478 // Get the mode
1479 mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
1480 line=find_vga_entry(mode);
1481 if(line==0xFF)return;
1482
1483 // Get the cursor pos for the page
1484 vga_get_cursor_pos(page,&dummy,&cursor);
1485 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1486
1487 // Get the dimensions
1488 nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
1489 nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1490
1491 switch(car)
1492 {
1493 case '\a': // ASCII 0x07, BEL
1494 //FIXME should beep
1495 break;
1496
1497 case '\b': // ASCII 0x08, BS
1498 if(xcurs>0)xcurs--;
1499 break;
1500
1501 case '\n': // ASCII 0x0A, LF
1502 ycurs++;
1503 break;
1504
1505 case '\r': // ASCII 0x0D, CR
1506 xcurs=0;
1507 break;
1508
1509 default:
1510
1511 if(vga_modes[line].class==TEXT)
1512 {
1513 // Compute the address
1514 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1515
1516 // Write the char
1517 write_byte(vga_modes[line].sstart,address,car);
1518
1519 if(flag==WITH_ATTR)
1520 write_byte(vga_modes[line].sstart,address+1,attr);
1521 }
1522 else
1523 {
1524 // FIXME gfx mode not complete
1525 cheight=video_param_table[line_to_vpti[line]].cheight;
1526 bpp=vga_modes[line].pixbits;
1527 switch(vga_modes[line].memmodel)
1528 {
1529 case PLANAR4:
1530 case PLANAR1:
1531 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
1532 break;
1533 case CGA:
1534 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1535 break;
1536 case LINEAR8:
1537 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1538 break;
1539#ifdef VGA_DEBUG
1540 default:
1541 unimplemented();
1542#endif
1543 }
1544 }
1545 xcurs++;
1546 // Do we need to wrap ?
1547 if(xcurs==nbcols)
1548 {xcurs=0;
1549 ycurs++;
1550 }
1551 }
1552
1553 // Do we need to scroll ?
1554 if(ycurs==nbrows)
1555 {
1556 if(vga_modes[line].class==TEXT)
1557 {
1558 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
1559 attr=read_byte(vga_modes[line].sstart,address+1);
1560 biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1561 }
1562 else
1563 {
1564 biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1565 }
1566 ycurs-=1;
1567 }
1568
1569 // Set the cursor for the page
1570 cursor=ycurs; cursor<<=8; cursor+=xcurs;
1571 biosfn_set_cursor_pos(page,cursor);
1572}
1573
1574// --------------------------------------------------------------------------------------------
1575static void get_font_access(void)
1576{
1577 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1578 outw(VGAREG_SEQU_ADDRESS, 0x0402);
1579 outw(VGAREG_SEQU_ADDRESS, 0x0704);
1580 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1581 outw(VGAREG_GRDC_ADDRESS, 0x0204);
1582 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1583 outw(VGAREG_GRDC_ADDRESS, 0x0406);
1584}
1585
1586static void release_font_access(void)
1587{
1588 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1589 outw(VGAREG_SEQU_ADDRESS, 0x0302);
1590 outw(VGAREG_SEQU_ADDRESS, 0x0304);
1591 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1592 outw(VGAREG_GRDC_ADDRESS, (((0x0a | ((inb(VGAREG_READ_MISC_OUTPUT) & 0x01) << 2)) << 8) | 0x06));
1593 outw(VGAREG_GRDC_ADDRESS, 0x0004);
1594 outw(VGAREG_GRDC_ADDRESS, 0x1005);
1595}
1596
1597static void set_scan_lines(uint8_t lines)
1598{
1599 uint16_t crtc_addr,cols,vde;
1600 uint8_t crtc_r9,ovl,rows;
1601
1602 crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
1603 outb(crtc_addr, 0x09);
1604 crtc_r9 = inb(crtc_addr+1);
1605 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
1606 outb(crtc_addr+1, crtc_r9);
1607 if(lines==8)
1608 {
1609 biosfn_set_cursor_shape(0x06,0x07);
1610 }
1611 else
1612 {
1613 biosfn_set_cursor_shape(lines-4,lines-3);
1614 }
1615 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
1616 outb(crtc_addr, 0x12);
1617 vde = inb(crtc_addr+1);
1618 outb(crtc_addr, 0x07);
1619 ovl = inb(crtc_addr+1);
1620 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
1621 rows = vde / lines;
1622 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
1623 cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1624 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
1625}
1626
1627static void biosfn_load_text_user_pat(uint8_t AL, uint16_t ES, uint16_t BP, uint16_t CX,
1628 uint16_t DX, uint8_t BL, uint8_t BH)
1629{
1630 uint16_t blockaddr,dest,i,src;
1631
1632 get_font_access();
1633 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1634 for(i=0;i<CX;i++)
1635 {
1636 src = BP + i * BH;
1637 dest = blockaddr + (DX + i) * 32;
1638 memcpyb(0xA000, dest, ES, src, BH);
1639 }
1640 release_font_access();
1641 if(AL>=0x10)
1642 {
1643 set_scan_lines(BH);
1644 }
1645}
1646
1647static void biosfn_load_text_8_14_pat(uint8_t AL, uint8_t BL)
1648{
1649 uint16_t blockaddr,dest,i,src;
1650
1651 get_font_access();
1652 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1653 for(i=0;i<0x100;i++)
1654 {
1655 src = i * 14;
1656 dest = blockaddr + i * 32;
1657 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont14+src, 14);
1658 }
1659 release_font_access();
1660 if(AL>=0x10)
1661 {
1662 set_scan_lines(14);
1663 }
1664}
1665
1666static void biosfn_load_text_8_8_pat(uint8_t AL, uint8_t BL)
1667{
1668 uint16_t blockaddr,dest,i,src;
1669
1670 get_font_access();
1671 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1672 for(i=0;i<0x100;i++)
1673 {
1674 src = i * 8;
1675 dest = blockaddr + i * 32;
1676 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont8+src, 8);
1677 }
1678 release_font_access();
1679 if(AL>=0x10)
1680 {
1681 set_scan_lines(8);
1682 }
1683}
1684
1685// --------------------------------------------------------------------------------------------
1686static void biosfn_load_text_8_16_pat(uint8_t AL, uint8_t BL)
1687{
1688 uint16_t blockaddr,dest,i,src;
1689
1690 get_font_access();
1691 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1692 for(i=0;i<0x100;i++)
1693 {
1694 src = i * 16;
1695 dest = blockaddr + i * 32;
1696 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont16+src, 16);
1697 }
1698 release_font_access();
1699 if(AL>=0x10)
1700 {
1701 set_scan_lines(16);
1702 }
1703}
1704
1705static void biosfn_load_gfx_8_8_chars(uint16_t ES, uint16_t BP)
1706{
1707#ifdef VGA_DEBUG
1708 unimplemented();
1709#endif
1710}
1711static void biosfn_load_gfx_user_chars(uint16_t ES, uint16_t BP, uint16_t CX,
1712 uint8_t BL, uint8_t DL)
1713{
1714#ifdef VGA_DEBUG
1715 unimplemented();
1716#endif
1717}
1718static void biosfn_load_gfx_8_14_chars(uint8_t BL)
1719{
1720#ifdef VGA_DEBUG
1721 unimplemented();
1722#endif
1723}
1724static void biosfn_load_gfx_8_8_dd_chars(uint8_t BL)
1725{
1726#ifdef VGA_DEBUG
1727 unimplemented();
1728#endif
1729}
1730static void biosfn_load_gfx_8_16_chars(uint8_t BL)
1731{
1732#ifdef VGA_DEBUG
1733 unimplemented();
1734#endif
1735}
1736// --------------------------------------------------------------------------------------------
1737static void biosfn_alternate_prtsc(void)
1738{
1739#ifdef VGA_DEBUG
1740 unimplemented();
1741#endif
1742}
1743
1744// --------------------------------------------------------------------------------------------
1745static void biosfn_switch_video_interface (AL,ES,DX) uint8_t AL;uint16_t ES;uint16_t DX;
1746{
1747#ifdef VGA_DEBUG
1748 unimplemented();
1749#endif
1750}
1751static void biosfn_enable_video_refresh_control(uint8_t AL)
1752{
1753#ifdef VGA_DEBUG
1754 unimplemented();
1755#endif
1756}
1757
1758// --------------------------------------------------------------------------------------------
1759static void biosfn_write_string(uint8_t flag, uint8_t page, uint8_t attr, uint16_t count,
1760 uint8_t row, uint8_t col, uint16_t seg, uint16_t offset)
1761{
1762 uint16_t newcurs,oldcurs,dummy;
1763 uint8_t car;
1764
1765 // Read curs info for the page
1766 vga_get_cursor_pos(page,&dummy,&oldcurs);
1767
1768 // if row=0xff special case : use current cursor position
1769 if(row==0xff)
1770 {col=oldcurs&0x00ff;
1771 row=(oldcurs&0xff00)>>8;
1772 }
1773
1774 newcurs=row; newcurs<<=8; newcurs+=col;
1775 biosfn_set_cursor_pos(page,newcurs);
1776
1777 while(count--!=0)
1778 {
1779 car=read_byte(seg,offset++);
1780 if((flag&0x02)!=0)
1781 attr=read_byte(seg,offset++);
1782
1783 biosfn_write_teletype(car,page,attr,WITH_ATTR);
1784 }
1785
1786 // Set back curs pos
1787 if((flag&0x01)==0)
1788 biosfn_set_cursor_pos(page,oldcurs);
1789}
1790
1791// --------------------------------------------------------------------------------------------
1792static void biosfn_read_state_info(uint16_t BX, uint16_t ES, uint16_t DI)
1793{
1794 // Address of static functionality table
1795 write_dword(ES,DI+0x00, (uint32_t)(void __far *)static_functionality);
1796
1797 // Hard coded copy from BIOS area. Should it be cleaner ?
1798 memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
1799 memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
1800
1801 write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
1802 write_byte(ES,DI+0x26,0);
1803 write_byte(ES,DI+0x27,16);
1804 write_byte(ES,DI+0x28,0);
1805 write_byte(ES,DI+0x29,8);
1806 write_byte(ES,DI+0x2a,2);
1807 write_byte(ES,DI+0x2b,0);
1808 write_byte(ES,DI+0x2c,0);
1809 write_byte(ES,DI+0x31,3);
1810 write_byte(ES,DI+0x32,0);
1811
1812 memsetb(ES,DI+0x33,0,13);
1813}
1814
1815// --------------------------------------------------------------------------------------------
1816uint16_t biosfn_read_video_state_size2(uint16_t state)
1817{
1818 uint16_t size;
1819
1820 size = 0;
1821 if (state & 1)
1822 size += 0x46;
1823
1824 if (state & 2)
1825 size += (5 + 8 + 5) * 2 + 6;
1826
1827 if (state & 4)
1828 size += 3 + 256 * 3 + 1;
1829
1830 return size;
1831}
1832
1833static void vga_get_video_state_size(uint16_t state, uint16_t STACK_BASED *size)
1834{
1835 /* The size is the number of 64-byte blocks required to save the state. */
1836 *size = (biosfn_read_video_state_size2(state) + 63) / 64;
1837}
1838
1839uint16_t biosfn_save_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
1840{
1841 uint16_t i, crtc_addr, ar_index;
1842
1843 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
1844 if (CX & 1) {
1845 write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
1846 write_byte(ES, BX, inb(crtc_addr)); BX++;
1847 write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
1848 inb(VGAREG_ACTL_RESET);
1849 ar_index = inb(VGAREG_ACTL_ADDRESS);
1850 write_byte(ES, BX, ar_index); BX++;
1851 write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
1852
1853 for(i=1;i<=4;i++){
1854 outb(VGAREG_SEQU_ADDRESS, i);
1855 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
1856 }
1857 outb(VGAREG_SEQU_ADDRESS, 0);
1858 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
1859
1860 for(i=0;i<=0x18;i++) {
1861 outb(crtc_addr,i);
1862 write_byte(ES, BX, inb(crtc_addr+1)); BX++;
1863 }
1864
1865 for(i=0;i<=0x13;i++) {
1866 inb(VGAREG_ACTL_RESET);
1867 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
1868 write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
1869 }
1870 inb(VGAREG_ACTL_RESET);
1871
1872 for(i=0;i<=8;i++) {
1873 outb(VGAREG_GRDC_ADDRESS,i);
1874 write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
1875 }
1876
1877 write_word(ES, BX, crtc_addr); BX+= 2;
1878
1879 /* XXX: read plane latches */
1880 write_byte(ES, BX, 0); BX++;
1881 write_byte(ES, BX, 0); BX++;
1882 write_byte(ES, BX, 0); BX++;
1883 write_byte(ES, BX, 0); BX++;
1884 }
1885 if (CX & 2) {
1886 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
1887 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
1888 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
1889 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
1890 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
1891 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
1892 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
1893 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
1894 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
1895 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
1896 for(i=0;i<8;i++) {
1897 write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
1898 BX += 2;
1899 }
1900 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
1901 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
1902 /* current font */
1903 write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
1904 write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
1905 write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
1906 write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
1907 }
1908 if (CX & 4) {
1909 /* XXX: check this */
1910 write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
1911 write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
1912 write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
1913 // Set the whole dac always, from 0
1914 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
1915 for(i=0;i<256*3;i++) {
1916 write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
1917 }
1918 write_byte(ES, BX, 0); BX++; /* color select register */
1919 }
1920 return BX;
1921}
1922
1923uint16_t biosfn_restore_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
1924{
1925 uint16_t i, crtc_addr, v, addr1, ar_index;
1926
1927 if (CX & 1) {
1928 // Reset Attribute Ctl flip-flop
1929 inb(VGAREG_ACTL_RESET);
1930
1931 crtc_addr = read_word(ES, BX + 0x40);
1932 addr1 = BX;
1933 BX += 5;
1934
1935 for(i=1;i<=4;i++){
1936 outb(VGAREG_SEQU_ADDRESS, i);
1937 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
1938 }
1939 outb(VGAREG_SEQU_ADDRESS, 0);
1940 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
1941
1942 // Disable CRTC write protection
1943 outw(crtc_addr,0x0011);
1944 // Set CRTC regs
1945 for(i=0;i<=0x18;i++) {
1946 if (i != 0x11) {
1947 outb(crtc_addr,i);
1948 outb(crtc_addr+1, read_byte(ES, BX));
1949 }
1950 BX++;
1951 }
1952 // select crtc base address
1953 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
1954 if (crtc_addr == 0x3d4)
1955 v |= 0x01;
1956 outb(VGAREG_WRITE_MISC_OUTPUT, v);
1957
1958 // enable write protection if needed
1959 outb(crtc_addr, 0x11);
1960 outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
1961
1962 // Set Attribute Ctl
1963 ar_index = read_byte(ES, addr1 + 0x03);
1964 inb(VGAREG_ACTL_RESET);
1965 for(i=0;i<=0x13;i++) {
1966 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
1967 outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
1968 }
1969 outb(VGAREG_ACTL_ADDRESS, ar_index);
1970 inb(VGAREG_ACTL_RESET);
1971
1972 for(i=0;i<=8;i++) {
1973 outb(VGAREG_GRDC_ADDRESS,i);
1974 outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
1975 }
1976 BX += 2; /* crtc_addr */
1977 BX += 4; /* plane latches */
1978
1979 outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
1980 outb(crtc_addr, read_byte(ES, addr1)); addr1++;
1981 outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
1982 addr1++;
1983 outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
1984 }
1985 if (CX & 2) {
1986 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
1987 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
1988 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
1989 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
1990 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
1991 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
1992 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
1993 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
1994 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
1995 write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
1996 for(i=0;i<8;i++) {
1997 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
1998 BX += 2;
1999 }
2000 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
2001 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
2002 /* current font */
2003 write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
2004 write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
2005 write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
2006 write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
2007 }
2008 if (CX & 4) {
2009 BX++;
2010 v = read_byte(ES, BX); BX++;
2011 outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
2012 // Set the whole dac always, from 0
2013 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
2014 for(i=0;i<256*3;i++) {
2015 outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
2016 }
2017 BX++;
2018 outb(VGAREG_DAC_WRITE_ADDRESS, v);
2019 }
2020 return BX;
2021}
2022
2023// ============================================================================================
2024//
2025// Video Utils
2026//
2027// ============================================================================================
2028
2029// --------------------------------------------------------------------------------------------
2030static uint8_t find_vga_entry(uint8_t mode)
2031{
2032 uint8_t i,line=0xFF;
2033 for(i=0;i<=MODE_MAX;i++)
2034 if(vga_modes[i].svgamode==mode)
2035 {line=i;
2036 break;
2037 }
2038 return line;
2039}
2040
2041/* =========================================================== */
2042/*
2043 * Misc Utils
2044*/
2045/* =========================================================== */
2046
2047uint8_t read_byte(uint16_t seg, uint16_t offset)
2048{
2049 return( *(seg:>(uint8_t *)offset) );
2050}
2051
2052void write_byte(uint16_t seg, uint16_t offset, uint8_t data)
2053{
2054 *(seg:>(uint8_t *)offset) = data;
2055}
2056
2057uint16_t read_word(uint16_t seg, uint16_t offset)
2058{
2059 return( *(seg:>(uint16_t *)offset) );
2060}
2061
2062void write_word(uint16_t seg, uint16_t offset, uint16_t data)
2063{
2064 *(seg:>(uint16_t *)offset) = data;
2065}
2066
2067uint32_t read_dword(uint16_t seg, uint16_t offset)
2068{
2069 return( *(seg:>(uint32_t *)offset) );
2070}
2071
2072void write_dword(uint16_t seg, uint16_t offset, uint32_t data)
2073{
2074 *(seg:>(uint32_t *)offset) = data;
2075}
2076
2077#ifdef VGA_DEBUG
2078void __cdecl unimplemented()
2079{
2080 printf("--> Unimplemented\n");
2081}
2082
2083void __cdecl unknown()
2084{
2085 printf("--> Unknown int10\n");
2086}
2087
2088#undef VBE_PRINTF_PORT
2089#define VBE_PRINTF_PORT 0x504
2090
2091// --------------------------------------------------------------------------------------------
2092void __cdecl printf(char *s, ...)
2093{
2094 char c;
2095 Boolean in_format;
2096 unsigned format_width, i;
2097 uint16_t arg, digit, nibble;
2098 uint16_t STACK_BASED *arg_ptr;
2099
2100 arg_ptr = (uint16_t STACK_BASED *)&s;
2101
2102 in_format = 0;
2103 format_width = 0;
2104
2105 while (c = *s) {
2106 if (c == '%') {
2107 in_format = 1;
2108 format_width = 0;
2109 } else if (in_format) {
2110 if ((c >= '0') && (c <= '9')) {
2111 format_width = (format_width * 10) + (c - '0');
2112 } else if (c == 'x') {
2113 arg_ptr++; // increment to next arg
2114 arg = *arg_ptr;
2115 if (format_width == 0)
2116 format_width = 4;
2117 i = 0;
2118 digit = format_width - 1;
2119 for (i = 0; i < format_width; i++) {
2120 nibble = (arg >> (4 * digit)) & 0x000f;
2121 if (nibble <= 9)
2122 outb(VBE_PRINTF_PORT, nibble + '0');
2123 else
2124 outb(VBE_PRINTF_PORT, (nibble - 10) + 'A');
2125 digit--;
2126 }
2127 in_format = 0;
2128 }
2129 //else if (c == 'd') {
2130 // in_format = 0;
2131 // }
2132 } else {
2133 outb(VBE_PRINTF_PORT, c);
2134 }
2135 ++s;
2136 }
2137}
2138#endif
2139
2140/// @todo rearrange, call only from VBE module?
2141extern void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI);
2142extern void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI);
2143extern void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI);
2144extern 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);
2145extern 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);
2146extern 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);
2147
2148
2149// --------------------------------------------------------------------------------------------
2150/*
2151 * int10 main dispatcher
2152 */
2153void __cdecl int10_func(uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP, uint16_t BX,
2154 uint16_t DX, uint16_t CX, uint16_t AX, uint16_t DS, uint16_t ES, uint16_t FLAGS)
2155{
2156
2157 // BIOS functions
2158 switch(GET_AH())
2159 {
2160 case 0x00:
2161 biosfn_set_video_mode(GET_AL());
2162 switch(GET_AL()&0x7F)
2163 {case 6:
2164 SET_AL(0x3F);
2165 break;
2166 case 0:
2167 case 1:
2168 case 2:
2169 case 3:
2170 case 4:
2171 case 5:
2172 case 7:
2173 SET_AL(0x30);
2174 break;
2175 default:
2176 SET_AL(0x20);
2177 }
2178 break;
2179 case 0x01:
2180 biosfn_set_cursor_shape(GET_CH(),GET_CL());
2181 break;
2182 case 0x02:
2183 biosfn_set_cursor_pos(GET_BH(),DX);
2184 break;
2185 case 0x03:
2186 vga_get_cursor_pos(GET_BH(), &CX, &DX);
2187 break;
2188 case 0x04:
2189 // Read light pen pos (unimplemented)
2190#ifdef VGA_DEBUG
2191 unimplemented();
2192#endif
2193 AX=0x00;
2194 BX=0x00;
2195 CX=0x00;
2196 DX=0x00;
2197 break;
2198 case 0x05:
2199 biosfn_set_active_page(GET_AL());
2200 break;
2201 case 0x06:
2202 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
2203 break;
2204 case 0x07:
2205 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
2206 break;
2207 case 0x08:
2208 vga_read_char_attr(GET_BH(), &AX);
2209 break;
2210 case 0x09:
2211 biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
2212 break;
2213 case 0x0A:
2214 biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
2215 break;
2216 case 0x0C:
2217 biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
2218 break;
2219 case 0x0D:
2220 vga_read_pixel(GET_BH(), CX, DX, &AX);
2221 break;
2222 case 0x0E:
2223 // Ralf Brown Interrupt list is WRONG on bh(page)
2224 // We do output only on the current page !
2225#ifdef VGA_DEBUG
2226 printf("write_teletype %02x\n", GET_AL());
2227#endif
2228
2229 biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
2230 break;
2231 case 0x10:
2232 // All other functions of group AH=0x10 rewritten in assembler
2233 biosfn_perform_gray_scale_summing(BX,CX);
2234 break;
2235 case 0x11:
2236 switch(GET_AL())
2237 {
2238 case 0x00:
2239 case 0x10:
2240 biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
2241 break;
2242 case 0x01:
2243 case 0x11:
2244 biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
2245 break;
2246 case 0x02:
2247 case 0x12:
2248 biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
2249 break;
2250 case 0x04:
2251 case 0x14:
2252 biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
2253 break;
2254 case 0x20:
2255 biosfn_load_gfx_8_8_chars(ES,BP);
2256 break;
2257 case 0x21:
2258 biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
2259 break;
2260 case 0x22:
2261 biosfn_load_gfx_8_14_chars(GET_BL());
2262 break;
2263 case 0x23:
2264 biosfn_load_gfx_8_8_dd_chars(GET_BL());
2265 break;
2266 case 0x24:
2267 biosfn_load_gfx_8_16_chars(GET_BL());
2268 break;
2269 case 0x30:
2270 vga_get_font_info(GET_BH(), &ES, &BP, &CX, &DX);
2271 break;
2272#ifdef VGA_DEBUG
2273 default:
2274 unknown();
2275#endif
2276 }
2277
2278 break;
2279 case 0x12:
2280 switch(GET_BL())
2281 {
2282 case 0x20:
2283 biosfn_alternate_prtsc();
2284 break;
2285 case 0x34: /* CGA text cursor emulation control. */
2286 if (GET_AL() < 2) {
2287 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,
2288 (read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & ~1) | GET_AL());
2289 SET_AL(0x12);
2290 }
2291 else
2292 SET_AL(0); /* Invalid argument. */
2293 break;
2294 case 0x35:
2295 biosfn_switch_video_interface(GET_AL(),ES,DX);
2296 SET_AL(0x12);
2297 break;
2298 case 0x36:
2299 biosfn_enable_video_refresh_control(GET_AL());
2300 SET_AL(0x12);
2301 break;
2302#ifdef VGA_DEBUG
2303 default:
2304 unknown();
2305#endif
2306 }
2307 break;
2308 case 0x13:
2309 biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
2310 break;
2311 case 0x1B:
2312 biosfn_read_state_info(BX,ES,DI);
2313 SET_AL(0x1B);
2314 break;
2315 case 0x1C:
2316 switch(GET_AL())
2317 {
2318 case 0x00:
2319 vga_get_video_state_size(CX,&BX);
2320 break;
2321 case 0x01:
2322 biosfn_save_video_state(CX,ES,BX);
2323 break;
2324 case 0x02:
2325 biosfn_restore_video_state(CX,ES,BX);
2326 break;
2327#ifdef VGA_DEBUG
2328 default:
2329 unknown();
2330#endif
2331 }
2332 SET_AL(0x1C);
2333 break;
2334
2335#ifdef VBE
2336 case 0x4f:
2337 if (vbe_has_vbe_display()) {
2338 switch(GET_AL())
2339 {
2340 case 0x00:
2341 vbe_biosfn_return_controller_information(&AX,ES,DI);
2342 break;
2343 case 0x01:
2344 vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
2345 break;
2346 case 0x02:
2347 vbe_biosfn_set_mode(&AX,BX,ES,DI);
2348 break;
2349 case 0x04:
2350 vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
2351 break;
2352 case 0x06:
2353 vbe_biosfn_get_set_scanline_length(&AX, &BX, &CX, &DX);
2354 break;
2355 case 0x09:
2356 //FIXME
2357#ifdef VGA_DEBUG
2358 unimplemented();
2359#endif
2360 // function failed
2361 AX=0x100;
2362 break;
2363 case 0x0A:
2364 //FIXME
2365#ifdef VGA_DEBUG
2366 unimplemented();
2367#endif
2368 // function failed
2369 AX=0x100;
2370 break;
2371 default:
2372#ifdef VGA_DEBUG
2373 unknown();
2374#endif
2375 // function failed
2376 AX=0x100;
2377 }
2378 }
2379 else {
2380 // No VBE display
2381 AX=0x0100;
2382 }
2383 break;
2384 case 0x56:
2385 if (vbe_has_vbe_display()) {
2386 switch(GET_AL())
2387 {
2388 case 0x42:
2389 private_biosfn_custom_mode(&AX,&BX,&CX,&DX);
2390 break;
2391 default:
2392 AX=0x0100;
2393 break;
2394 }
2395 } else {
2396 // No VBE display
2397 AX=0x0100;
2398 }
2399 break;
2400#endif
2401
2402#ifdef VGA_DEBUG
2403 default:
2404 unknown();
2405#endif
2406 }
2407}
2408
2409#ifdef VBE
2410//#include "vbe.c"
2411#endif
2412
2413#ifdef CIRRUS
2414#include "clext.c"
2415#endif
2416
2417// --------------------------------------------------------------------------------------------
2418
Note: See TracBrowser for help on using the repository browser.

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