VirtualBox

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

Last change on this file since 78292 was 75149, checked in by vboxsync, 6 years ago

BIOS: Added custom video mode set function not limited by the list of available VBE modes (bugref:9273).

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