VirtualBox

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

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

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use