VirtualBox

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

Last change on this file since 50920 was 50920, checked in by vboxsync, 11 years ago

VGABIOS: Do not increment TTY line position twice when LF is sent at rightmost column.

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

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