VirtualBox

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

Last change on this file since 65381 was 63562, checked in by vboxsync, 8 years ago

scm: cleaning up todos

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