VirtualBox

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

Last change on this file since 43609 was 43152, checked in by vboxsync, 12 years ago

VGABIOS: Allow building with DEBUG_VGA again.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.5 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
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 7:
1417 //FIXME should beep
1418 break;
1419
1420 case 8:
1421 if(xcurs>0)xcurs--;
1422 break;
1423
1424 case '\r':
1425 xcurs=0;
1426 break;
1427
1428 case '\n':
1429 ycurs++;
1430 break;
1431
1432 case '\t':
1433 do
1434 {
1435 biosfn_write_teletype(' ',page,attr,flag);
1436 vga_get_cursor_pos(page,&dummy,&cursor);
1437 xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
1438 }while(xcurs%8==0);
1439 break;
1440
1441 default:
1442
1443 if(vga_modes[line].class==TEXT)
1444 {
1445 // Compute the address
1446 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
1447
1448 // Write the char
1449 write_byte(vga_modes[line].sstart,address,car);
1450
1451 if(flag==WITH_ATTR)
1452 write_byte(vga_modes[line].sstart,address+1,attr);
1453 }
1454 else
1455 {
1456 // FIXME gfx mode not complete
1457 cheight=video_param_table[line_to_vpti[line]].cheight;
1458 bpp=vga_modes[line].pixbits;
1459 switch(vga_modes[line].memmodel)
1460 {
1461 case PLANAR4:
1462 case PLANAR1:
1463 write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
1464 break;
1465 case CGA:
1466 write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
1467 break;
1468 case LINEAR8:
1469 write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
1470 break;
1471#ifdef VGA_DEBUG
1472 default:
1473 unimplemented();
1474#endif
1475 }
1476 }
1477 xcurs++;
1478 }
1479
1480 // Do we need to wrap ?
1481 if(xcurs==nbcols)
1482 {xcurs=0;
1483 ycurs++;
1484 }
1485
1486 // Do we need to scroll ?
1487 if(ycurs==nbrows)
1488 {
1489 if(vga_modes[line].class==TEXT)
1490 {
1491 address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
1492 attr=read_byte(vga_modes[line].sstart,address+1);
1493 biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1494 }
1495 else
1496 {
1497 biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
1498 }
1499 ycurs-=1;
1500 }
1501
1502 // Set the cursor for the page
1503 cursor=ycurs; cursor<<=8; cursor+=xcurs;
1504 biosfn_set_cursor_pos(page,cursor);
1505}
1506
1507// --------------------------------------------------------------------------------------------
1508static void get_font_access(void)
1509{
1510 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1511 outw(VGAREG_SEQU_ADDRESS, 0x0402);
1512 outw(VGAREG_SEQU_ADDRESS, 0x0704);
1513 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1514 outw(VGAREG_GRDC_ADDRESS, 0x0204);
1515 outw(VGAREG_GRDC_ADDRESS, 0x0005);
1516 outw(VGAREG_GRDC_ADDRESS, 0x0406);
1517}
1518
1519static void release_font_access(void)
1520{
1521 outw(VGAREG_SEQU_ADDRESS, 0x0100);
1522 outw(VGAREG_SEQU_ADDRESS, 0x0302);
1523 outw(VGAREG_SEQU_ADDRESS, 0x0304);
1524 outw(VGAREG_SEQU_ADDRESS, 0x0300);
1525 outw(VGAREG_GRDC_ADDRESS, (((0x0a | ((inb(VGAREG_READ_MISC_OUTPUT) & 0x01) << 2)) << 8) | 0x06));
1526 outw(VGAREG_GRDC_ADDRESS, 0x0004);
1527 outw(VGAREG_GRDC_ADDRESS, 0x1005);
1528}
1529
1530static void set_scan_lines(uint8_t lines)
1531{
1532 uint16_t crtc_addr,cols,vde;
1533 uint8_t crtc_r9,ovl,rows;
1534
1535 crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
1536 outb(crtc_addr, 0x09);
1537 crtc_r9 = inb(crtc_addr+1);
1538 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
1539 outb(crtc_addr+1, crtc_r9);
1540 if(lines==8)
1541 {
1542 biosfn_set_cursor_shape(0x06,0x07);
1543 }
1544 else
1545 {
1546 biosfn_set_cursor_shape(lines-4,lines-3);
1547 }
1548 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
1549 outb(crtc_addr, 0x12);
1550 vde = inb(crtc_addr+1);
1551 outb(crtc_addr, 0x07);
1552 ovl = inb(crtc_addr+1);
1553 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
1554 rows = vde / lines;
1555 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
1556 cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
1557 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
1558}
1559
1560static void biosfn_load_text_user_pat(uint8_t AL, uint16_t ES, uint16_t BP, uint16_t CX,
1561 uint16_t DX, uint8_t BL, uint8_t BH)
1562{
1563 uint16_t blockaddr,dest,i,src;
1564
1565 get_font_access();
1566 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1567 for(i=0;i<CX;i++)
1568 {
1569 src = BP + i * BH;
1570 dest = blockaddr + (DX + i) * 32;
1571 memcpyb(0xA000, dest, ES, src, BH);
1572 }
1573 release_font_access();
1574 if(AL>=0x10)
1575 {
1576 set_scan_lines(BH);
1577 }
1578}
1579
1580static void biosfn_load_text_8_14_pat(uint8_t AL, uint8_t BL)
1581{
1582 uint16_t blockaddr,dest,i,src;
1583
1584 get_font_access();
1585 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1586 for(i=0;i<0x100;i++)
1587 {
1588 src = i * 14;
1589 dest = blockaddr + i * 32;
1590 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont14+src, 14);
1591 }
1592 release_font_access();
1593 if(AL>=0x10)
1594 {
1595 set_scan_lines(14);
1596 }
1597}
1598
1599static void biosfn_load_text_8_8_pat(uint8_t AL, uint8_t BL)
1600{
1601 uint16_t blockaddr,dest,i,src;
1602
1603 get_font_access();
1604 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1605 for(i=0;i<0x100;i++)
1606 {
1607 src = i * 8;
1608 dest = blockaddr + i * 32;
1609 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont8+src, 8);
1610 }
1611 release_font_access();
1612 if(AL>=0x10)
1613 {
1614 set_scan_lines(8);
1615 }
1616}
1617
1618// --------------------------------------------------------------------------------------------
1619static void biosfn_load_text_8_16_pat(uint8_t AL, uint8_t BL)
1620{
1621 uint16_t blockaddr,dest,i,src;
1622
1623 get_font_access();
1624 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
1625 for(i=0;i<0x100;i++)
1626 {
1627 src = i * 16;
1628 dest = blockaddr + i * 32;
1629 memcpyb(0xA000, dest, 0xC000, (uint16_t)vgafont16+src, 16);
1630 }
1631 release_font_access();
1632 if(AL>=0x10)
1633 {
1634 set_scan_lines(16);
1635 }
1636}
1637
1638static void biosfn_load_gfx_8_8_chars(uint16_t ES, uint16_t BP)
1639{
1640#ifdef VGA_DEBUG
1641 unimplemented();
1642#endif
1643}
1644static void biosfn_load_gfx_user_chars(uint16_t ES, uint16_t BP, uint16_t CX,
1645 uint8_t BL, uint8_t DL)
1646{
1647#ifdef VGA_DEBUG
1648 unimplemented();
1649#endif
1650}
1651static void biosfn_load_gfx_8_14_chars(uint8_t BL)
1652{
1653#ifdef VGA_DEBUG
1654 unimplemented();
1655#endif
1656}
1657static void biosfn_load_gfx_8_8_dd_chars(uint8_t BL)
1658{
1659#ifdef VGA_DEBUG
1660 unimplemented();
1661#endif
1662}
1663static void biosfn_load_gfx_8_16_chars(uint8_t BL)
1664{
1665#ifdef VGA_DEBUG
1666 unimplemented();
1667#endif
1668}
1669// --------------------------------------------------------------------------------------------
1670static void biosfn_alternate_prtsc(void)
1671{
1672#ifdef VGA_DEBUG
1673 unimplemented();
1674#endif
1675}
1676
1677// --------------------------------------------------------------------------------------------
1678static void biosfn_switch_video_interface (AL,ES,DX) uint8_t AL;uint16_t ES;uint16_t DX;
1679{
1680#ifdef VGA_DEBUG
1681 unimplemented();
1682#endif
1683}
1684static void biosfn_enable_video_refresh_control(uint8_t AL)
1685{
1686#ifdef VGA_DEBUG
1687 unimplemented();
1688#endif
1689}
1690
1691// --------------------------------------------------------------------------------------------
1692static void biosfn_write_string(uint8_t flag, uint8_t page, uint8_t attr, uint16_t count,
1693 uint8_t row, uint8_t col, uint16_t seg, uint16_t offset)
1694{
1695 uint16_t newcurs,oldcurs,dummy;
1696 uint8_t car;
1697
1698 // Read curs info for the page
1699 vga_get_cursor_pos(page,&dummy,&oldcurs);
1700
1701 // if row=0xff special case : use current cursor position
1702 if(row==0xff)
1703 {col=oldcurs&0x00ff;
1704 row=(oldcurs&0xff00)>>8;
1705 }
1706
1707 newcurs=row; newcurs<<=8; newcurs+=col;
1708 biosfn_set_cursor_pos(page,newcurs);
1709
1710 while(count--!=0)
1711 {
1712 car=read_byte(seg,offset++);
1713 if((flag&0x02)!=0)
1714 attr=read_byte(seg,offset++);
1715
1716 biosfn_write_teletype(car,page,attr,WITH_ATTR);
1717 }
1718
1719 // Set back curs pos
1720 if((flag&0x01)==0)
1721 biosfn_set_cursor_pos(page,oldcurs);
1722}
1723
1724// --------------------------------------------------------------------------------------------
1725static void biosfn_read_state_info(uint16_t BX, uint16_t ES, uint16_t DI)
1726{
1727 // Address of static functionality table
1728 write_dword(ES,DI+0x00, (uint32_t)(void __far *)static_functionality);
1729
1730 // Hard coded copy from BIOS area. Should it be cleaner ?
1731 memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
1732 memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
1733
1734 write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
1735 write_byte(ES,DI+0x26,0);
1736 write_byte(ES,DI+0x27,16);
1737 write_byte(ES,DI+0x28,0);
1738 write_byte(ES,DI+0x29,8);
1739 write_byte(ES,DI+0x2a,2);
1740 write_byte(ES,DI+0x2b,0);
1741 write_byte(ES,DI+0x2c,0);
1742 write_byte(ES,DI+0x31,3);
1743 write_byte(ES,DI+0x32,0);
1744
1745 memsetb(ES,DI+0x33,0,13);
1746}
1747
1748// --------------------------------------------------------------------------------------------
1749uint16_t biosfn_read_video_state_size2(uint16_t state)
1750{
1751 uint16_t size;
1752
1753 size = 0;
1754 if (state & 1)
1755 size += 0x46;
1756
1757 if (state & 2)
1758 size += (5 + 8 + 5) * 2 + 6;
1759
1760 if (state & 4)
1761 size += 3 + 256 * 3 + 1;
1762
1763 //@todo: Is this supposed to be in 1-byte or 64-byte units?
1764 return size;
1765}
1766
1767static void vga_get_video_state_size(uint16_t state, uint16_t STACK_BASED *size)
1768{
1769 *size = biosfn_read_video_state_size2(state);
1770}
1771
1772uint16_t biosfn_save_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
1773{
1774 uint16_t i, crtc_addr, ar_index;
1775
1776 crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
1777 if (CX & 1) {
1778 write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
1779 write_byte(ES, BX, inb(crtc_addr)); BX++;
1780 write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
1781 inb(VGAREG_ACTL_RESET);
1782 ar_index = inb(VGAREG_ACTL_ADDRESS);
1783 write_byte(ES, BX, ar_index); BX++;
1784 write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
1785
1786 for(i=1;i<=4;i++){
1787 outb(VGAREG_SEQU_ADDRESS, i);
1788 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
1789 }
1790 outb(VGAREG_SEQU_ADDRESS, 0);
1791 write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
1792
1793 for(i=0;i<=0x18;i++) {
1794 outb(crtc_addr,i);
1795 write_byte(ES, BX, inb(crtc_addr+1)); BX++;
1796 }
1797
1798 for(i=0;i<=0x13;i++) {
1799 inb(VGAREG_ACTL_RESET);
1800 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
1801 write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
1802 }
1803 inb(VGAREG_ACTL_RESET);
1804
1805 for(i=0;i<=8;i++) {
1806 outb(VGAREG_GRDC_ADDRESS,i);
1807 write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
1808 }
1809
1810 write_word(ES, BX, crtc_addr); BX+= 2;
1811
1812 /* XXX: read plane latches */
1813 write_byte(ES, BX, 0); BX++;
1814 write_byte(ES, BX, 0); BX++;
1815 write_byte(ES, BX, 0); BX++;
1816 write_byte(ES, BX, 0); BX++;
1817 }
1818 if (CX & 2) {
1819 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
1820 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
1821 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
1822 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
1823 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
1824 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
1825 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
1826 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
1827 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
1828 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
1829 for(i=0;i<8;i++) {
1830 write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
1831 BX += 2;
1832 }
1833 write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
1834 write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
1835 /* current font */
1836 write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
1837 write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
1838 write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
1839 write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
1840 }
1841 if (CX & 4) {
1842 /* XXX: check this */
1843 write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
1844 write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
1845 write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
1846 // Set the whole dac always, from 0
1847 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
1848 for(i=0;i<256*3;i++) {
1849 write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
1850 }
1851 write_byte(ES, BX, 0); BX++; /* color select register */
1852 }
1853 return BX;
1854}
1855
1856uint16_t biosfn_restore_video_state(uint16_t CX, uint16_t ES, uint16_t BX)
1857{
1858 uint16_t i, crtc_addr, v, addr1, ar_index;
1859
1860 if (CX & 1) {
1861 // Reset Attribute Ctl flip-flop
1862 inb(VGAREG_ACTL_RESET);
1863
1864 crtc_addr = read_word(ES, BX + 0x40);
1865 addr1 = BX;
1866 BX += 5;
1867
1868 for(i=1;i<=4;i++){
1869 outb(VGAREG_SEQU_ADDRESS, i);
1870 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
1871 }
1872 outb(VGAREG_SEQU_ADDRESS, 0);
1873 outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
1874
1875 // Disable CRTC write protection
1876 outw(crtc_addr,0x0011);
1877 // Set CRTC regs
1878 for(i=0;i<=0x18;i++) {
1879 if (i != 0x11) {
1880 outb(crtc_addr,i);
1881 outb(crtc_addr+1, read_byte(ES, BX));
1882 }
1883 BX++;
1884 }
1885 // select crtc base address
1886 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
1887 if (crtc_addr == 0x3d4)
1888 v |= 0x01;
1889 outb(VGAREG_WRITE_MISC_OUTPUT, v);
1890
1891 // enable write protection if needed
1892 outb(crtc_addr, 0x11);
1893 outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
1894
1895 // Set Attribute Ctl
1896 ar_index = read_byte(ES, addr1 + 0x03);
1897 inb(VGAREG_ACTL_RESET);
1898 for(i=0;i<=0x13;i++) {
1899 outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
1900 outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
1901 }
1902 outb(VGAREG_ACTL_ADDRESS, ar_index);
1903 inb(VGAREG_ACTL_RESET);
1904
1905 for(i=0;i<=8;i++) {
1906 outb(VGAREG_GRDC_ADDRESS,i);
1907 outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
1908 }
1909 BX += 2; /* crtc_addr */
1910 BX += 4; /* plane latches */
1911
1912 outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
1913 outb(crtc_addr, read_byte(ES, addr1)); addr1++;
1914 outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
1915 addr1++;
1916 outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
1917 }
1918 if (CX & 2) {
1919 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
1920 write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
1921 write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
1922 write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
1923 write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
1924 write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
1925 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
1926 write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
1927 write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
1928 write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
1929 for(i=0;i<8;i++) {
1930 write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
1931 BX += 2;
1932 }
1933 write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
1934 write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
1935 /* current font */
1936 write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
1937 write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
1938 write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
1939 write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
1940 }
1941 if (CX & 4) {
1942 BX++;
1943 v = read_byte(ES, BX); BX++;
1944 outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
1945 // Set the whole dac always, from 0
1946 outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
1947 for(i=0;i<256*3;i++) {
1948 outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
1949 }
1950 BX++;
1951 outb(VGAREG_DAC_WRITE_ADDRESS, v);
1952 }
1953 return BX;
1954}
1955
1956// ============================================================================================
1957//
1958// Video Utils
1959//
1960// ============================================================================================
1961
1962// --------------------------------------------------------------------------------------------
1963static uint8_t find_vga_entry(uint8_t mode)
1964{
1965 uint8_t i,line=0xFF;
1966 for(i=0;i<=MODE_MAX;i++)
1967 if(vga_modes[i].svgamode==mode)
1968 {line=i;
1969 break;
1970 }
1971 return line;
1972}
1973
1974/* =========================================================== */
1975/*
1976 * Misc Utils
1977*/
1978/* =========================================================== */
1979
1980uint8_t read_byte(uint16_t seg, uint16_t offset)
1981{
1982 return( *(seg:>(uint8_t *)offset) );
1983}
1984
1985void write_byte(uint16_t seg, uint16_t offset, uint8_t data)
1986{
1987 *(seg:>(uint8_t *)offset) = data;
1988}
1989
1990uint16_t read_word(uint16_t seg, uint16_t offset)
1991{
1992 return( *(seg:>(uint16_t *)offset) );
1993}
1994
1995void write_word(uint16_t seg, uint16_t offset, uint16_t data)
1996{
1997 *(seg:>(uint16_t *)offset) = data;
1998}
1999
2000uint32_t read_dword(uint16_t seg, uint16_t offset)
2001{
2002 return( *(seg:>(uint32_t *)offset) );
2003}
2004
2005void write_dword(uint16_t seg, uint16_t offset, uint32_t data)
2006{
2007 *(seg:>(uint32_t *)offset) = data;
2008}
2009
2010#ifdef VGA_DEBUG
2011void __cdecl unimplemented()
2012{
2013 printf("--> Unimplemented\n");
2014}
2015
2016void __cdecl unknown()
2017{
2018 printf("--> Unknown int10\n");
2019}
2020
2021#undef VBE_PRINTF_PORT
2022#define VBE_PRINTF_PORT 0x504
2023
2024// --------------------------------------------------------------------------------------------
2025void __cdecl printf(char *s, ...)
2026{
2027 char c;
2028 Boolean in_format;
2029 unsigned format_width, i;
2030 uint16_t arg, digit, nibble;
2031 uint16_t STACK_BASED *arg_ptr;
2032
2033 arg_ptr = (uint16_t STACK_BASED *)&s;
2034
2035 in_format = 0;
2036 format_width = 0;
2037
2038 while (c = *s) {
2039 if (c == '%') {
2040 in_format = 1;
2041 format_width = 0;
2042 } else if (in_format) {
2043 if ((c >= '0') && (c <= '9')) {
2044 format_width = (format_width * 10) + (c - '0');
2045 } else if (c == 'x') {
2046 arg_ptr++; // increment to next arg
2047 arg = *arg_ptr;
2048 if (format_width == 0)
2049 format_width = 4;
2050 i = 0;
2051 digit = format_width - 1;
2052 for (i = 0; i < format_width; i++) {
2053 nibble = (arg >> (4 * digit)) & 0x000f;
2054 if (nibble <= 9)
2055 outb(VBE_PRINTF_PORT, nibble + '0');
2056 else
2057 outb(VBE_PRINTF_PORT, (nibble - 10) + 'A');
2058 digit--;
2059 }
2060 in_format = 0;
2061 }
2062 //else if (c == 'd') {
2063 // in_format = 0;
2064 // }
2065 } else {
2066 outb(VBE_PRINTF_PORT, c);
2067 }
2068 ++s;
2069 }
2070}
2071#endif
2072
2073//@todo: rearrange, call only from VBE module?
2074extern void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI);
2075extern void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI);
2076extern void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI);
2077extern 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);
2078
2079// --------------------------------------------------------------------------------------------
2080/*
2081 * int10 main dispatcher
2082 */
2083void __cdecl int10_func(uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP, uint16_t BX,
2084 uint16_t DX, uint16_t CX, uint16_t AX, uint16_t DS, uint16_t ES, uint16_t FLAGS)
2085{
2086
2087 // BIOS functions
2088 switch(GET_AH())
2089 {
2090 case 0x00:
2091 biosfn_set_video_mode(GET_AL());
2092 switch(GET_AL()&0x7F)
2093 {case 6:
2094 SET_AL(0x3F);
2095 break;
2096 case 0:
2097 case 1:
2098 case 2:
2099 case 3:
2100 case 4:
2101 case 5:
2102 case 7:
2103 SET_AL(0x30);
2104 break;
2105 default:
2106 SET_AL(0x20);
2107 }
2108 break;
2109 case 0x01:
2110 biosfn_set_cursor_shape(GET_CH(),GET_CL());
2111 break;
2112 case 0x02:
2113 biosfn_set_cursor_pos(GET_BH(),DX);
2114 break;
2115 case 0x03:
2116 vga_get_cursor_pos(GET_BH(), &CX, &DX);
2117 break;
2118 case 0x04:
2119 // Read light pen pos (unimplemented)
2120#ifdef VGA_DEBUG
2121 unimplemented();
2122#endif
2123 AX=0x00;
2124 BX=0x00;
2125 CX=0x00;
2126 DX=0x00;
2127 break;
2128 case 0x05:
2129 biosfn_set_active_page(GET_AL());
2130 break;
2131 case 0x06:
2132 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
2133 break;
2134 case 0x07:
2135 biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
2136 break;
2137 case 0x08:
2138 vga_read_char_attr(GET_BH(), &AX);
2139 break;
2140 case 0x09:
2141 biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
2142 break;
2143 case 0x0A:
2144 biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
2145 break;
2146 case 0x0C:
2147 biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
2148 break;
2149 case 0x0D:
2150 vga_read_pixel(GET_BH(), CX, DX, &AX);
2151 break;
2152 case 0x0E:
2153 // Ralf Brown Interrupt list is WRONG on bh(page)
2154 // We do output only on the current page !
2155#ifdef VGA_DEBUG
2156 printf("write_teletype %02x\n", GET_AL());
2157#endif
2158
2159 biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
2160 break;
2161 case 0x10:
2162 // All other functions of group AH=0x10 rewritten in assembler
2163 biosfn_perform_gray_scale_summing(BX,CX);
2164 break;
2165 case 0x11:
2166 switch(GET_AL())
2167 {
2168 case 0x00:
2169 case 0x10:
2170 biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
2171 break;
2172 case 0x01:
2173 case 0x11:
2174 biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
2175 break;
2176 case 0x02:
2177 case 0x12:
2178 biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
2179 break;
2180 case 0x04:
2181 case 0x14:
2182 biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
2183 break;
2184 case 0x20:
2185 biosfn_load_gfx_8_8_chars(ES,BP);
2186 break;
2187 case 0x21:
2188 biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
2189 break;
2190 case 0x22:
2191 biosfn_load_gfx_8_14_chars(GET_BL());
2192 break;
2193 case 0x23:
2194 biosfn_load_gfx_8_8_dd_chars(GET_BL());
2195 break;
2196 case 0x24:
2197 biosfn_load_gfx_8_16_chars(GET_BL());
2198 break;
2199 case 0x30:
2200 vga_get_font_info(GET_BH(), &ES, &BP, &CX, &DX);
2201 break;
2202#ifdef VGA_DEBUG
2203 default:
2204 unknown();
2205#endif
2206 }
2207
2208 break;
2209 case 0x12:
2210 switch(GET_BL())
2211 {
2212 case 0x20:
2213 biosfn_alternate_prtsc();
2214 break;
2215 case 0x35:
2216 biosfn_switch_video_interface(GET_AL(),ES,DX);
2217 SET_AL(0x12);
2218 break;
2219 case 0x36:
2220 biosfn_enable_video_refresh_control(GET_AL());
2221 SET_AL(0x12);
2222 break;
2223#ifdef VGA_DEBUG
2224 default:
2225 unknown();
2226#endif
2227 }
2228 break;
2229 case 0x13:
2230 biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
2231 break;
2232 case 0x1B:
2233 biosfn_read_state_info(BX,ES,DI);
2234 SET_AL(0x1B);
2235 break;
2236 case 0x1C:
2237 switch(GET_AL())
2238 {
2239 case 0x00:
2240 vga_get_video_state_size(CX,&BX);
2241 break;
2242 case 0x01:
2243 biosfn_save_video_state(CX,ES,BX);
2244 break;
2245 case 0x02:
2246 biosfn_restore_video_state(CX,ES,BX);
2247 break;
2248#ifdef VGA_DEBUG
2249 default:
2250 unknown();
2251#endif
2252 }
2253 SET_AL(0x1C);
2254 break;
2255
2256#ifdef VBE
2257 case 0x4f:
2258 if (vbe_has_vbe_display()) {
2259 switch(GET_AL())
2260 {
2261 case 0x00:
2262 vbe_biosfn_return_controller_information(&AX,ES,DI);
2263 break;
2264 case 0x01:
2265 vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
2266 break;
2267 case 0x02:
2268 vbe_biosfn_set_mode(&AX,BX,ES,DI);
2269 break;
2270 case 0x04:
2271 vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
2272 break;
2273 case 0x09:
2274 //FIXME
2275#ifdef VGA_DEBUG
2276 unimplemented();
2277#endif
2278 // function failed
2279 AX=0x100;
2280 break;
2281 case 0x0A:
2282 //FIXME
2283#ifdef VGA_DEBUG
2284 unimplemented();
2285#endif
2286 // function failed
2287 AX=0x100;
2288 break;
2289 default:
2290#ifdef VGA_DEBUG
2291 unknown();
2292#endif
2293 // function failed
2294 AX=0x100;
2295 }
2296 }
2297 else {
2298 // No VBE display
2299 AX=0x0100;
2300 }
2301 break;
2302#endif
2303
2304#ifdef VGA_DEBUG
2305 default:
2306 unknown();
2307#endif
2308 }
2309}
2310
2311#ifdef VBE
2312//#include "vbe.c"
2313#endif
2314
2315#ifdef CIRRUS
2316#include "clext.c"
2317#endif
2318
2319// --------------------------------------------------------------------------------------------
2320
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