VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/BIOS/vbe.c@ 67813

Last change on this file since 67813 was 67813, checked in by vboxsync, 7 years ago

VGABIOS: Fixed 15bpp virtual resolution calculations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.8 KB
Line 
1// ============================================================================================
2//
3// Copyright (C) 2002 Jeroen Janssen
4//
5// This library is free software; you can redistribute it and/or
6// modify it under the terms of the GNU Lesser General Public
7// License as published by the Free Software Foundation; either
8// version 2 of the License, or (at your option) any later version.
9//
10// This library is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public
16// License along with this library; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18//
19// ============================================================================================
20//
21// This VBE is part of the VGA Bios specific to the plex86/bochs Emulated VGA card.
22// You can NOT drive any physical vga card with it.
23//
24// ============================================================================================
25//
26// This VBE Bios is based on information taken from :
27// - VESA BIOS EXTENSION (VBE) Core Functions Standard Version 3.0 located at www.vesa.org
28//
29// ============================================================================================
30
31
32/*
33 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
34 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
35 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
36 * a choice of LGPL license versions is made available with the language indicating
37 * that LGPLv2 or any later version may be used, or where a choice of which version
38 * of the LGPL is applied is otherwise unspecified.
39 */
40
41// Use VBE new dynamic mode list. Note that without this option, no
42// checks are currently done to make sure that modes fit into the
43// framebuffer!
44#define VBE_NEW_DYN_LIST
45
46#include <inttypes.h>
47#include <stddef.h>
48#include "vbe.h"
49#include "vgadefs.h"
50#include "inlines.h"
51
52// disable VESA/VBE2 check in vbe info
53//#define VBE2_NO_VESA_CHECK
54
55// use bytewise i/o (Longhorn beta issue, not in released Vista)
56#define VBE_BYTEWISE_IO
57
58#ifdef VBE_BYTEWISE_IO
59 extern void do_out_dx_ax();
60 #pragma aux do_out_dx_ax "*";
61 extern void out_w(uint16_t port, uint16_t value);
62 #pragma aux out_w = \
63 "call do_out_dx_ax" \
64 parm [dx] [ax] modify nomemory;
65 extern void do_in_ax_dx();
66 #pragma aux do_in_ax_dx "*";
67 extern uint16_t in_w(uint16_t port);
68 #pragma aux in_w = \
69 "call do_in_ax_dx" \
70 parm [dx] value [ax] modify nomemory;
71#else
72 #define out_w outw
73 #define in_w inw
74#endif
75
76
77/* VESA signatures as integer constants. */
78#define SIG_VBE2 0x32454256 /* 'VBE2' */
79#define SIG_VESA 0x41534556 /* 'VESA' */
80
81
82/* Implemented in assembler. */
83extern void __cdecl vga_compat_setup(void);
84extern void dispi_set_enable(uint16_t enable);
85extern void dispi_set_bank(uint16_t bank);
86extern uint16_t __cdecl dispi_get_max_bpp(void);
87extern void __cdecl dispi_set_bank_farcall(void);
88
89// The current OEM Software Revision of this VBE Bios
90#define VBE_OEM_SOFTWARE_REV 0x0003
91
92// FIXME: 'merge' these (c) etc strings with the vgabios.c strings?
93char vbebios_copyright[] = "VirtualBox VESA BIOS";
94char vbebios_vendor_name[] = VBOX_VENDOR;
95char vbebios_product_name[] = VBOX_PRODUCT " VBE Adapter";
96char vbebios_product_revision[] = VBOX_PRODUCT " Version " VBOX_VERSION_STRING;
97
98char vbebios_info_string[] = "VirtualBox VBE Display Adapter enabled\r\n\r\n";
99char no_vbebios_info_string[] = "No VirtualBox VBE support available!\r\n\r\n";
100
101#ifdef VGA_DEBUG
102char msg_vbe_init[] = "VirtualBox Version " VBOX_VERSION_STRING " VBE Display Adapter\r\n";
103#endif
104
105static void dispi_set_xres(uint16_t xres)
106{
107#ifdef VGA_DEBUG
108 printf("vbe_set_xres: %04x\n", xres);
109#endif
110 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
111 out_w(VBE_DISPI_IOPORT_DATA, xres);
112}
113
114static void dispi_set_yres(uint16_t yres)
115{
116#ifdef VGA_DEBUG
117 printf("vbe_set_yres: %04x\n", yres);
118#endif
119 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
120 out_w(VBE_DISPI_IOPORT_DATA, yres);
121}
122
123static uint16_t dispi_get_yres(void)
124{
125 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
126 return in_w(VBE_DISPI_IOPORT_DATA);
127}
128
129static void dispi_set_bpp(uint16_t bpp)
130{
131#ifdef VGA_DEBUG
132 printf("vbe_set_bpp: %02x\n", bpp);
133#endif
134 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
135 out_w(VBE_DISPI_IOPORT_DATA, bpp);
136}
137
138static uint16_t dispi_get_bpp(void)
139{
140 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
141 return in_w(VBE_DISPI_IOPORT_DATA);
142}
143
144static void dispi_set_virt_width(uint16_t vwidth)
145{
146#ifdef VGA_DEBUG
147 printf("vbe_set_virt_width: %04x\n", vwidth);
148#endif
149 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
150 out_w(VBE_DISPI_IOPORT_DATA, vwidth);
151}
152
153static uint16_t dispi_get_virt_width(void)
154{
155 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
156 return in_w(VBE_DISPI_IOPORT_DATA);
157}
158
159static uint16_t dispi_get_virt_height(void)
160{
161 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_HEIGHT);
162 return in_w(VBE_DISPI_IOPORT_DATA);
163}
164
165uint16_t in_word(uint16_t port, uint16_t addr)
166{
167 outw(port, addr);
168 return inw(port);
169}
170
171#ifdef VBE_NEW_DYN_LIST
172uint8_t in_byte(uint16_t port, uint16_t addr)
173{
174 outw(port, addr);
175 return inb(port);
176}
177#endif
178
179/* Display "chip" identification helpers. */
180static uint16_t dispi_get_id(void)
181{
182 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
183 return inw(VBE_DISPI_IOPORT_DATA);
184}
185
186static void dispi_set_id(uint16_t chip_id)
187{
188 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
189 outw(VBE_DISPI_IOPORT_DATA, chip_id);
190}
191
192/* VBE Init - Initialise the VESA BIOS Extension (VBE) support
193 * This function does a sanity check on the host side display code interface.
194 */
195void vbe_init(void)
196{
197 dispi_set_id(VBE_DISPI_ID0);
198 if (dispi_get_id() == VBE_DISPI_ID0) {
199 /* VBE support was detected. */
200 write_byte(BIOSMEM_SEG, BIOSMEM_VBE_FLAG, 1);
201 dispi_set_id(VBE_DISPI_ID4);
202 }
203#ifdef DEBUG_VGA
204 printf(msg_vbe_init);
205#endif
206}
207
208/* Find the offset of the desired mode, given its number. */
209#ifdef VBE_NEW_DYN_LIST
210static uint16_t mode_info_find_mode(uint16_t mode, Boolean using_lfb)
211{
212 uint16_t sig, vmode, attrs;
213 uint16_t cur_info_ofs; /* Current offset in mode list. */
214
215 /* Read and check the VBE Extra Data signature. */
216 sig = in_word(VBE_EXTRA_PORT, 0);
217 if (sig != VBEHEADER_MAGIC) {
218#ifdef DEBUG_VGA
219 printf("Signature NOT found! %x\n", sig);
220#endif
221 return 0;
222 }
223
224 cur_info_ofs = sizeof(VBEHeader);
225
226 vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, mode)/*&cur_info->mode*/);
227 while (vmode != VBE_VESA_MODE_END_OF_LIST)
228 {
229 attrs = in_word(VBE_EXTRA_PORT, /*&cur_info->info.ModeAttributes*/cur_info_ofs + offsetof(ModeInfoListItem, info.ModeAttributes) );
230
231 if (vmode == mode)
232 {
233 if (!using_lfb)
234 return cur_info_ofs;
235 else if (attrs & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
236 return cur_info_ofs;
237 else {
238 cur_info_ofs += sizeof(ModeInfoListItem);
239 vmode = in_word(VBE_EXTRA_PORT, /*&cur_info->mode*/cur_info_ofs + offsetof(ModeInfoListItem, mode));
240 }
241 } else {
242 cur_info_ofs += sizeof(ModeInfoListItem);
243 vmode = in_word(VBE_EXTRA_PORT, /*&cur_info->mode*/cur_info_ofs + offsetof(ModeInfoListItem, mode));
244 }
245 }
246 return 0;
247}
248#else
249static ModeInfoListItem* mode_info_find_mode(uint16_t mode, Boolean using_lfb)
250{
251 ModeInfoListItem *cur_info = &mode_info_list;
252
253 while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST)
254 {
255 if (cur_info->mode == mode)
256 {
257 if (!using_lfb)
258 return cur_info;
259 else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
260 return cur_info;
261 else
262 cur_info++;
263 } else
264 cur_info++;
265 }
266 return 0;
267}
268#endif
269
270#ifndef VBOX
271; VBE Display Info - Display information on screen about the VBE
272
273vbe_display_info:
274 call _vbe_has_vbe_display
275 test ax, ax
276 jz no_vbe_flag
277 mov ax, #0xc000
278 mov ds, ax
279 mov si, #_vbebios_info_string
280 jmp _display_string
281no_vbe_flag:
282 mov ax, #0xc000
283 mov ds, ax
284 mov si, #_no_vbebios_info_string
285 jmp _display_string
286#endif
287
288/** Function 00h - Return VBE Controller Information
289 *
290 * Input:
291 * AX = 4F00h
292 * ES:DI = Pointer to buffer in which to place VbeInfoBlock structure
293 * (VbeSignature should be VBE2 when VBE 2.0 information is desired and
294 * the info block is 512 bytes in size)
295 * Output:
296 * AX = VBE Return Status
297 *
298 */
299void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI)
300{
301 uint16_t status;
302 uint16_t vbe2_info;
303 uint16_t cur_mode = 0;
304 uint16_t cur_ptr=34;
305#ifdef VBE_NEW_DYN_LIST
306 uint16_t cur_info_ofs;
307 uint16_t sig, vmode;
308#else
309 ModeInfoListItem *cur_info = &mode_info_list;
310#endif
311 uint16_t max_bpp = dispi_get_max_bpp();
312 VbeInfoBlock __far *info_block;
313
314 info_block = ES :> (VbeInfoBlock *)DI;
315
316#ifdef VBE_NEW_DYN_LIST
317 /* Read VBE Extra Data signature */
318 sig = in_word(VBE_EXTRA_PORT, 0);
319 if (sig != VBEHEADER_MAGIC)
320 {
321 *AX = 0x0100;
322#ifdef DEBUG_VGA
323 printf("Signature NOT found\n");
324#endif
325 return;
326 }
327 cur_info_ofs = sizeof(VBEHeader);
328#endif
329 status = *AX;
330
331#ifdef VGA_DEBUG
332 printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status);
333#endif
334
335 vbe2_info = 0;
336
337 /* Don't use a local copy of VbeInfoBlock on the stack; it's too big.
338 * The Ubuntu 8.04 64 bits splash screen emulator can't handle this.
339 */
340#ifdef VBE2_NO_VESA_CHECK
341#else /* !VBE2_NO_VESA_CHECK */
342 // check for VBE2 signature
343 if (info_block->VbeSignature.Sig32 == SIG_VBE2 || info_block->VbeSignature.Sig32 == SIG_VESA)
344 {
345 vbe2_info = 1;
346#ifdef VGA_DEBUG
347 printf("VBE correct VESA/VBE2 signature found\n");
348#endif
349 }
350#endif /* !VBE2_NO_VESA_CHECK */
351
352 /* VBE Signature - the compiler will optimize this into something sane. */
353 info_block->VbeSignature.SigChr[0] = 'V';
354 info_block->VbeSignature.SigChr[1] = 'E';
355 info_block->VbeSignature.SigChr[2] = 'S';
356 info_block->VbeSignature.SigChr[3] = 'A';
357
358 /* VBE Version supported. */
359 info_block->VbeVersion = 0x0200; /* Version 2.0. */
360
361 /* OEM String. */
362 info_block->OemString.Ptr = &vbebios_copyright;
363
364 /* Capabilities if this implementation. */
365 info_block->Capabilities[0] = VBE_CAPABILITY_8BIT_DAC;
366 info_block->Capabilities[1] = 0;
367 info_block->Capabilities[2] = 0;
368 info_block->Capabilities[3] = 0;
369
370 /* Video mode list pointer (dynamically generated). */
371 info_block->VideoModePtr_Seg = ES;
372 info_block->VideoModePtr_Off = DI + 34;
373
374 /* Total controller memory in 64K units. */
375 info_block->TotalMemory = in_word(VBE_EXTRA_PORT, 0xffff);
376
377 if (vbe2_info)
378 {
379 /* OEM information. */
380 info_block->OemSoftwareRev = VBE_OEM_SOFTWARE_REV;
381 info_block->OemVendorName.Ptr = &vbebios_vendor_name;
382 info_block->OemProductName.Ptr = &vbebios_product_name;
383 info_block->OemProductRev.Ptr = &vbebios_product_revision;
384 }
385
386#ifdef VBE_NEW_DYN_LIST
387 do
388 {
389 uint8_t data_b;
390
391 data_b = in_byte(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.BitsPerPixel) /*&cur_info->info.BitsPerPixel*/);
392 if (data_b <= max_bpp)
393 {
394 vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, mode)/*&cur_info->mode*/);
395#ifdef VGA_DEBUG
396 printf("VBE found mode %x => %x\n", vmode, cur_mode);
397#endif
398 write_word(ES, DI + cur_ptr, vmode);
399 cur_mode++;
400 cur_ptr+=2;
401 }
402 cur_info_ofs += sizeof(ModeInfoListItem);
403 vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, mode)/*&cur_info->mode*/);
404 } while (vmode != VBE_VESA_MODE_END_OF_LIST);
405
406 // Add vesa mode list terminator
407 write_word(ES, DI + cur_ptr, vmode);
408#else
409 do
410 {
411 if (cur_info->info.BitsPerPixel <= max_bpp) {
412#ifdef VGA_DEBUG
413 printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode);
414#endif
415 write_word(ES, DI + cur_ptr, cur_info->mode);
416 cur_mode++;
417 cur_ptr += 2;
418 }
419 cur_info++;
420 } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST);
421
422 // Add vesa mode list terminator
423 write_word(ES, DI + cur_ptr, cur_info->mode);
424#endif // VBE_NEW_DYN_LIST
425 *AX = 0x004F;
426}
427
428/** Function 01h - Return VBE Mode Information
429 *
430 * Input:
431 * AX = 4F01h
432 * CX = Mode Number
433 * ES:DI = Pointer to buffer in which to place ModeInfoBlock structure
434 * Output:
435 * AX = VBE Return Status
436 *
437 */
438void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI)
439{
440 uint16_t result = 0x0100;
441#ifdef VBE_NEW_DYN_LIST
442 uint16_t cur_info_ofs;
443#else
444 ModeInfoListItem *cur_info;
445#endif
446 Boolean using_lfb;
447 uint8_t win_attr;
448
449#ifdef VGA_DEBUG
450 printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX);
451#endif
452
453 using_lfb = ((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
454 CX = (CX & 0x1ff);
455
456#ifdef VBE_NEW_DYN_LIST
457 cur_info_ofs = mode_info_find_mode(CX, using_lfb);
458
459 if (cur_info_ofs) {
460 uint16_t i;
461#else
462 cur_info = mode_info_find_mode(CX, using_lfb);
463
464 if (cur_info != 0) {
465#endif
466#ifdef VGA_DEBUG
467 printf("VBE found mode %x\n",CX);
468#endif
469 memsetb(ES, DI, 0, 256); // The mode info size is fixed
470#ifdef VBE_NEW_DYN_LIST
471 for (i = 0; i < sizeof(ModeInfoBlockCompact); i++) {
472 uint8_t b;
473
474 b = in_byte(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info) + i/*(char *)(&(cur_info->info)) + i*/);
475 write_byte(ES, DI + i, b);
476 }
477#else
478 memcpyb(ES, DI, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact));
479#endif
480 win_attr = read_byte(ES, DI + offsetof(ModeInfoBlock, WinAAttributes));
481 if (win_attr & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
482 write_word(ES, DI + offsetof(ModeInfoBlock, WinFuncPtr), (uint16_t)(dispi_set_bank_farcall));
483 // If BIOS not at 0xC000 -> boom
484 write_word(ES, DI + offsetof(ModeInfoBlock, WinFuncPtr) + 2, 0xC000);
485 }
486 // Update the LFB physical address which may change at runtime
487 out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_FB_BASE_HI);
488 write_word(ES, DI + offsetof(ModeInfoBlock, PhysBasePtr) + 2, in_w(VBE_DISPI_IOPORT_DATA));
489
490 result = 0x4f;
491 } else {
492#ifdef VGA_DEBUG
493 printf("VBE *NOT* found mode %x\n",CX);
494#endif
495 result = 0x100;
496 }
497
498 *AX = result;
499}
500
501/** Function 02h - Set VBE Mode
502 *
503 * Input:
504 * AX = 4F02h
505 * BX = Desired Mode to set
506 * ES:DI = Pointer to CRTCInfoBlock structure
507 * Output:
508 * AX = VBE Return Status
509 *
510 */
511void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI)
512{
513 uint16_t result;
514#ifdef VBE_NEW_DYN_LIST
515 uint16_t cur_info_ofs;
516#else
517 ModeInfoListItem *cur_info;
518#endif
519 Boolean using_lfb;
520 uint8_t no_clear;
521 uint8_t lfb_flag;
522
523 using_lfb = ((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
524 lfb_flag = using_lfb ? VBE_DISPI_LFB_ENABLED : 0;
525 no_clear = ((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY) ? VBE_DISPI_NOCLEARMEM : 0;
526
527 BX = (BX & 0x1ff);
528
529 // check for non vesa mode
530 if (BX < VBE_MODE_VESA_DEFINED)
531 {
532 uint8_t mode;
533
534 dispi_set_enable(VBE_DISPI_DISABLED);
535 // call the vgabios in order to set the video mode
536 // this allows for going back to textmode with a VBE call (some applications expect that to work)
537 mode = (BX & 0xff);
538 biosfn_set_video_mode(mode);
539 result = 0x4f;
540 goto leave;
541 }
542
543#ifdef VBE_NEW_DYN_LIST
544 cur_info_ofs = mode_info_find_mode(BX, using_lfb);
545
546 if (cur_info_ofs != 0)
547 {
548 uint16_t xres, yres;
549 uint8_t bpp;
550
551 xres = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.XResolution) /*&cur_info->info.XResolution*/);
552 yres = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.YResolution) /*&cur_info->info.YResolution*/);
553 bpp = in_byte(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.BitsPerPixel) /*&cur_info->info.BitsPerPixel*/);
554
555#ifdef VGA_DEBUG
556 printf("VBE found mode %x, setting:\n", BX);
557 printf("\txres%x yres%x bpp%x\n", xres, yres, bpp);
558#endif
559#else
560 cur_info = mode_info_find_mode(BX, using_lfb);
561
562 if (cur_info != 0)
563 {
564#ifdef VGA_DEBUG
565 printf("VBE found mode %x, setting:\n", BX);
566 printf("\txres%x yres%x bpp%x\n",
567 cur_info->info.XResolution,
568 cur_info->info.YResolution,
569 cur_info->info.BitsPerPixel);
570#endif
571#endif // VBE_NEW_DYN_LIST
572
573 // first disable current mode (when switching between vesa modi)
574 dispi_set_enable(VBE_DISPI_DISABLED);
575
576#ifdef VBE_NEW_DYN_LIST
577 if (bpp == 4)
578#else
579 if (cur_info->info.BitsPerPixel == 4)
580#endif
581 {
582 biosfn_set_video_mode(0x6a);
583 }
584
585#ifdef VBE_NEW_DYN_LIST
586 dispi_set_bpp(bpp);
587 dispi_set_xres(xres);
588 dispi_set_yres(yres);
589#else
590 dispi_set_bpp(cur_info->info.BitsPerPixel);
591 dispi_set_xres(cur_info->info.XResolution);
592 dispi_set_yres(cur_info->info.YResolution);
593#endif
594 dispi_set_bank(0);
595 dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
596 vga_compat_setup();
597
598 write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
599 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
600
601 result = 0x4f;
602 }
603 else
604 {
605#ifdef VGA_DEBUG
606 printf("VBE *NOT* found mode %x\n" , BX);
607#endif
608 result = 0x100;
609 }
610
611leave:
612 *AX = result;
613}
614
615uint16_t vbe_biosfn_read_video_state_size(void)
616{
617 return 9 * 2;
618}
619
620void vbe_biosfn_save_video_state(uint16_t ES, uint16_t BX)
621{
622 uint16_t enable, i;
623
624 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
625 enable = inw(VBE_DISPI_IOPORT_DATA);
626 write_word(ES, BX, enable);
627 BX += 2;
628 if (!(enable & VBE_DISPI_ENABLED))
629 return;
630 for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
631 if (i != VBE_DISPI_INDEX_ENABLE) {
632 outw(VBE_DISPI_IOPORT_INDEX, i);
633 write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
634 BX += 2;
635 }
636 }
637}
638
639
640void vbe_biosfn_restore_video_state(uint16_t ES, uint16_t BX)
641{
642 uint16_t enable, i;
643
644 enable = read_word(ES, BX);
645 BX += 2;
646
647 if (!(enable & VBE_DISPI_ENABLED)) {
648 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
649 outw(VBE_DISPI_IOPORT_DATA, enable);
650 } else {
651 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
652 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
653 BX += 2;
654 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
655 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
656 BX += 2;
657 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
658 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
659 BX += 2;
660 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
661 outw(VBE_DISPI_IOPORT_DATA, enable);
662
663 for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
664 outw(VBE_DISPI_IOPORT_INDEX, i);
665 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
666 BX += 2;
667 }
668 }
669}
670
671/** Function 04h - Save/Restore State
672 *
673 * Input:
674 * AX = 4F04h
675 * DL = 00h Return Save/Restore State buffer size
676 * 01h Save State
677 * 02h Restore State
678 * CX = Requested states
679 * ES:BX = Pointer to buffer (if DL <> 00h)
680 * Output:
681 * AX = VBE Return Status
682 * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h)
683 *
684 */
685void vbe_biosfn_save_restore_state(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t DX,
686 uint16_t ES, uint16_t STACK_BASED *BX)
687{
688 uint16_t result, val;
689
690 result = 0x004F;
691 switch(GET_DL()) {
692 case 0x00:
693 val = biosfn_read_video_state_size2(CX);
694#ifdef VGA_DEBUG
695 printf("VGA state size=%x\n", val);
696#endif
697 if (CX & 8)
698 val += vbe_biosfn_read_video_state_size();
699 *BX = (val + 63) / 64;
700 break;
701 case 0x01:
702 val = *BX;
703 val = biosfn_save_video_state(CX, ES, val);
704#ifdef VGA_DEBUG
705 printf("VGA save_state offset=%x\n", val);
706#endif
707 if (CX & 8)
708 vbe_biosfn_save_video_state(ES, val);
709 break;
710 case 0x02:
711 val = *BX;
712 val = biosfn_restore_video_state(CX, ES, val);
713#ifdef VGA_DEBUG
714 printf("VGA restore_state offset=%x\n", val);
715#endif
716 if (CX & 8)
717 vbe_biosfn_restore_video_state(ES, val);
718 break;
719 default:
720 // function failed
721 result = 0x100;
722 break;
723 }
724 *AX = result;
725}
726
727/** Function 06h - Set/Get Logical Scan Line Length
728 *
729 * Input:
730 * AX = 4F06h
731 * BL = 00h Set Scan Line Length in Pixels
732 * = 01h Get Scan Line Length
733 * = 02h Set Scan Line Length in Bytes
734 * = 03h Get Maximum Scan Line Length
735 * CX = If BL=00h Desired Width in Pixels
736 * If BL=02h Desired Width in Bytes
737 * (Ignored for Get Functions)
738 *
739 * Output:
740 * AX = VBE Return Status
741 * BX = Bytes Per Scan Line
742 * CX = Actual Pixels Per Scan Line (truncated to
743 * nearest complete pixel)
744 * DX = Maximum Number of Scan Lines
745 */
746void vbe_biosfn_get_set_scanline_length(uint16_t STACK_BASED *AX, uint16_t STACK_BASED *BX,
747 uint16_t STACK_BASED *CX, uint16_t STACK_BASED *DX)
748{
749 uint16_t val;
750 uint16_t result;
751 uint8_t bpp;
752 uint8_t subfn;
753 uint16_t old_vw;
754
755 bpp = dispi_get_bpp();
756 bpp = bpp == 15 ? 16 : bpp;
757 old_vw = dispi_get_virt_width();
758 result = 0x004F;
759 val = *CX;
760 subfn = *BX & 0xFF;
761#ifdef VGA_DEBUG
762 printf("VBE get/set scanline len fn=%x, CX=%x\n", subfn, *CX);
763#endif
764 switch(subfn) {
765 case 0x02:
766 if (bpp == 4)
767 val = val * 8;
768 else
769 val = val / (bpp / 8);
770 /* fall through */
771 case 0x00:
772 dispi_set_virt_width(val);
773 /* fall through */
774 case 0x01:
775 val = dispi_get_virt_width();
776 *CX = val; /* Width in pixels. */
777 if (bpp == 4)
778 val = val / 8;
779 else
780 val = val * (bpp / 8);
781 val = (val + 3) & ~3;
782 *BX = val; /* Bytes per scanline. */
783 *DX = dispi_get_virt_height(); /* Height in lines. */
784 if (*DX < dispi_get_yres()) {
785 dispi_set_virt_width(old_vw);
786 result = 0x200;
787 }
788 break;
789 default:
790 // function failed
791 result = 0x100;
792 break;
793 }
794 *AX = result;
795}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use