• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // defines available
33 
34 // disable VESA/VBE2 check in vbe info
35 //#define VBE2_NO_VESA_CHECK
36 
37 
38 #include "vbe.h"
39 #include "vbetables.h"
40 
41 // The current OEM Software Revision of this VBE Bios
42 #define VBE_OEM_SOFTWARE_REV 0x0002;
43 
44 extern char vbebios_copyright;
45 extern char vbebios_vendor_name;
46 extern char vbebios_product_name;
47 extern char vbebios_product_revision;
48 
49 ASM_START
50 // FIXME: 'merge' these (c) etc strings with the vgabios.c strings?
51 _vbebios_copyright:
52 .ascii       "Bochs/Plex86 VBE(C) 2003 http://savannah.nongnu.org/projects/vgabios/"
53 .byte        0x00
54 
55 _vbebios_vendor_name:
56 .ascii       "Bochs/Plex86 Developers"
57 .byte        0x00
58 
59 _vbebios_product_name:
60 .ascii       "Bochs/Plex86 VBE Adapter"
61 .byte        0x00
62 
63 _vbebios_product_revision:
64 .ascii       "$Id$"
65 .byte        0x00
66 
67 _vbebios_info_string:
68 .ascii      "Bochs VBE Display Adapter enabled"
69 .byte	0x0a,0x0d
70 .byte	0x0a,0x0d
71 .byte	0x00
72 
73 _no_vbebios_info_string:
74 .ascii      "NO Bochs VBE Support available!"
75 .byte	0x0a,0x0d
76 .byte	0x0a,0x0d
77 .byte 0x00
78 
79 #if defined(USE_BX_INFO) || defined(DEBUG)
80 msg_vbe_init:
81 .ascii      "VBE Bios $Id$"
82 .byte	0x0a,0x0d, 0x00
83 #endif
84 
85   .align 2
86 vesa_pm_start:
87   dw vesa_pm_set_window - vesa_pm_start
88   dw vesa_pm_set_display_start - vesa_pm_start
89   dw vesa_pm_unimplemented - vesa_pm_start
90   dw vesa_pm_io_ports_table - vesa_pm_start
91 vesa_pm_io_ports_table:
92   dw VBE_DISPI_IOPORT_INDEX
93   dw VBE_DISPI_IOPORT_INDEX + 1
94   dw VBE_DISPI_IOPORT_DATA
95   dw VBE_DISPI_IOPORT_DATA + 1
96   dw 0xffff
97   dw 0xffff
98 
99   USE32
100 vesa_pm_set_window:
101   cmp  bx, #0x00
102   je  vesa_pm_set_display_window1
103   mov  ax, #0x0100
104   ret
105 vesa_pm_set_display_window1:
106   mov  ax, dx
107   push dx
108   push ax
109   mov  dx, # VBE_DISPI_IOPORT_INDEX
110   mov  ax, # VBE_DISPI_INDEX_BANK
111   out  dx, ax
112   pop  ax
113   mov  dx, # VBE_DISPI_IOPORT_DATA
114   out  dx, ax
115   in   ax, dx
116   pop  dx
117   cmp  dx, ax
118   jne  illegal_window
119   mov  ax, #0x004f
120   ret
121 illegal_window:
122   mov  ax, #0x014f
123   ret
124 
125 vesa_pm_set_display_start:
126   cmp  bl, #0x80
127   je   vesa_pm_set_display_start1
128   cmp  bl, #0x00
129   je   vesa_pm_set_display_start1
130   mov  ax, #0x0100
131   ret
132 vesa_pm_set_display_start1:
133 ; convert offset to (X, Y) coordinate
134 ; (would be simpler to change Bochs VBE API...)
135   push eax
136   push ecx
137   push edx
138   push esi
139   push edi
140   shl edx, #16
141   and ecx, #0xffff
142   or ecx, edx
143   shl ecx, #2
144   mov eax, ecx
145 
146   push eax
147   mov  dx, # VBE_DISPI_IOPORT_INDEX
148   mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
149   out  dx, ax
150   mov  dx, # VBE_DISPI_IOPORT_DATA
151   in   ax, dx
152   movzx ecx, ax
153 
154   mov  dx, # VBE_DISPI_IOPORT_INDEX
155   mov  ax, # VBE_DISPI_INDEX_BPP
156   out  dx, ax
157   mov  dx, # VBE_DISPI_IOPORT_DATA
158   in   ax, dx
159   movzx esi, ax
160   pop  eax
161 
162   cmp esi, #4
163   jz bpp4_mode
164   add esi, #7
165   shr esi, #3
166   imul ecx, esi
167   xor edx, edx
168   div ecx
169   mov edi, eax
170   mov eax, edx
171   xor edx, edx
172   div esi
173   jmp set_xy_regs
174 
175 bpp4_mode:
176   shr ecx, #1
177   xor edx, edx
178   div ecx
179   mov edi, eax
180   mov eax, edx
181   shl eax, #1
182 
183 set_xy_regs:
184   push dx
185   push ax
186   mov  dx, # VBE_DISPI_IOPORT_INDEX
187   mov  ax, # VBE_DISPI_INDEX_X_OFFSET
188   out  dx, ax
189   pop  ax
190   mov  dx, # VBE_DISPI_IOPORT_DATA
191   out  dx, ax
192   pop  dx
193 
194   mov  ax, di
195   push dx
196   push ax
197   mov  dx, # VBE_DISPI_IOPORT_INDEX
198   mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
199   out  dx, ax
200   pop  ax
201   mov  dx, # VBE_DISPI_IOPORT_DATA
202   out  dx, ax
203   pop  dx
204 
205   pop edi
206   pop esi
207   pop edx
208   pop ecx
209   pop eax
210   mov  ax, #0x004f
211   ret
212 
213 vesa_pm_unimplemented:
214   mov ax, #0x014f
215   ret
216   USE16
217 vesa_pm_end:
218 
219 ; DISPI ioport functions
220 
221 dispi_get_id:
222   push dx
223   mov  dx, # VBE_DISPI_IOPORT_INDEX
224   mov  ax, # VBE_DISPI_INDEX_ID
225   out  dx, ax
226   mov  dx, # VBE_DISPI_IOPORT_DATA
227   in   ax, dx
228   pop  dx
229   ret
230 
231 dispi_set_id:
232   push dx
233   push ax
234   mov  dx, # VBE_DISPI_IOPORT_INDEX
235   mov  ax, # VBE_DISPI_INDEX_ID
236   out  dx, ax
237   pop  ax
238   mov  dx, # VBE_DISPI_IOPORT_DATA
239   out  dx, ax
240   pop  dx
241   ret
242 ASM_END
243 
dispi_set_xres(xres)244 static void dispi_set_xres(xres)
245   Bit16u xres;
246 {
247 ASM_START
248   push bp
249   mov  bp, sp
250   push ax
251   push dx
252 
253   mov  dx, # VBE_DISPI_IOPORT_INDEX
254   mov  ax, # VBE_DISPI_INDEX_XRES
255   out  dx, ax
256   mov  dx, # VBE_DISPI_IOPORT_DATA
257   mov  ax, 4[bp] ; xres
258   out  dx, ax
259 
260   pop  dx
261   pop  ax
262   pop  bp
263 ASM_END
264 }
265 
dispi_set_yres(yres)266 static void dispi_set_yres(yres)
267   Bit16u yres;
268 {
269   outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_YRES);
270   outw(VBE_DISPI_IOPORT_DATA,yres);
271 }
272 
dispi_set_bpp(bpp)273 static void dispi_set_bpp(bpp)
274   Bit16u bpp;
275 {
276   outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_BPP);
277   outw(VBE_DISPI_IOPORT_DATA,bpp);
278 }
279 
280 ASM_START
281 ; AL = bits per pixel / AH = bytes per pixel
282 dispi_get_bpp:
283   push dx
284   mov  dx, # VBE_DISPI_IOPORT_INDEX
285   mov  ax, # VBE_DISPI_INDEX_BPP
286   out  dx, ax
287   mov  dx, # VBE_DISPI_IOPORT_DATA
288   in   ax, dx
289   mov  ah, al
290   shr  ah, 3
291   test al, #0x07
292   jz   get_bpp_noinc
293   inc  ah
294 get_bpp_noinc:
295   pop  dx
296   ret
297 
298 ; get display capabilities
299 
300 _dispi_get_max_xres:
301   push dx
302   push bx
303   call dispi_get_enable
304   mov  bx, ax
305   or   ax, # VBE_DISPI_GETCAPS
306   call _dispi_set_enable
307   mov  dx, # VBE_DISPI_IOPORT_INDEX
308   mov  ax, # VBE_DISPI_INDEX_XRES
309   out  dx, ax
310   mov  dx, # VBE_DISPI_IOPORT_DATA
311   in   ax, dx
312   push ax
313   mov  ax, bx
314   call _dispi_set_enable
315   pop  ax
316   pop  bx
317   pop  dx
318   ret
319 
320 _dispi_get_max_bpp:
321   push dx
322   push bx
323   call dispi_get_enable
324   mov  bx, ax
325   or   ax, # VBE_DISPI_GETCAPS
326   call _dispi_set_enable
327   mov  dx, # VBE_DISPI_IOPORT_INDEX
328   mov  ax, # VBE_DISPI_INDEX_BPP
329   out  dx, ax
330   mov  dx, # VBE_DISPI_IOPORT_DATA
331   in   ax, dx
332   push ax
333   mov  ax, bx
334   call _dispi_set_enable
335   pop  ax
336   pop  bx
337   pop  dx
338   ret
339 
340 _dispi_set_enable:
341   push dx
342   push ax
343   mov  dx, # VBE_DISPI_IOPORT_INDEX
344   mov  ax, # VBE_DISPI_INDEX_ENABLE
345   out  dx, ax
346   pop  ax
347   mov  dx, # VBE_DISPI_IOPORT_DATA
348   out  dx, ax
349   pop  dx
350   ret
351 
352 dispi_get_enable:
353   push dx
354   mov  dx, # VBE_DISPI_IOPORT_INDEX
355   mov  ax, # VBE_DISPI_INDEX_ENABLE
356   out  dx, ax
357   mov  dx, # VBE_DISPI_IOPORT_DATA
358   in   ax, dx
359   pop  dx
360   ret
361 
362 _dispi_set_bank:
363   push dx
364   push ax
365   mov  dx, # VBE_DISPI_IOPORT_INDEX
366   mov  ax, # VBE_DISPI_INDEX_BANK
367   out  dx, ax
368   pop  ax
369   mov  dx, # VBE_DISPI_IOPORT_DATA
370   out  dx, ax
371   pop  dx
372   ret
373 
374 dispi_get_bank:
375   push dx
376   mov  dx, # VBE_DISPI_IOPORT_INDEX
377   mov  ax, # VBE_DISPI_INDEX_BANK
378   out  dx, ax
379   mov  dx, # VBE_DISPI_IOPORT_DATA
380   in   ax, dx
381   pop  dx
382   ret
383 ASM_END
384 
385 static void dispi_set_bank_farcall()
386 {
387 ASM_START
388   cmp bx,#0x0100
389   je dispi_set_bank_farcall_get
390   or bx,bx
391   jnz dispi_set_bank_farcall_error
392   mov ax,dx
393   push dx
394   push ax
395   mov ax,# VBE_DISPI_INDEX_BANK
396   mov dx,# VBE_DISPI_IOPORT_INDEX
397   out dx,ax
398   pop ax
399   mov dx,# VBE_DISPI_IOPORT_DATA
400   out dx,ax
401   in  ax,dx
402   pop dx
403   cmp dx,ax
404   jne dispi_set_bank_farcall_error
405   mov ax, #0x004f
406   retf
407 dispi_set_bank_farcall_get:
408   mov ax,# VBE_DISPI_INDEX_BANK
409   mov dx,# VBE_DISPI_IOPORT_INDEX
410   out dx,ax
411   mov dx,# VBE_DISPI_IOPORT_DATA
412   in ax,dx
413   mov dx,ax
414   retf
415 dispi_set_bank_farcall_error:
416   mov ax,#0x014F
417   retf
418 ASM_END
419 }
420 
421 ASM_START
422 dispi_set_x_offset:
423   push dx
424   push ax
425   mov  dx, # VBE_DISPI_IOPORT_INDEX
426   mov  ax, # VBE_DISPI_INDEX_X_OFFSET
427   out  dx, ax
428   pop  ax
429   mov  dx, # VBE_DISPI_IOPORT_DATA
430   out  dx, ax
431   pop  dx
432   ret
433 
434 dispi_get_x_offset:
435   push dx
436   mov  dx, # VBE_DISPI_IOPORT_INDEX
437   mov  ax, # VBE_DISPI_INDEX_X_OFFSET
438   out  dx, ax
439   mov  dx, # VBE_DISPI_IOPORT_DATA
440   in   ax, dx
441   pop  dx
442   ret
443 
444 dispi_set_y_offset:
445   push dx
446   push ax
447   mov  dx, # VBE_DISPI_IOPORT_INDEX
448   mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
449   out  dx, ax
450   pop  ax
451   mov  dx, # VBE_DISPI_IOPORT_DATA
452   out  dx, ax
453   pop  dx
454   ret
455 
456 dispi_get_y_offset:
457   push dx
458   mov  dx, # VBE_DISPI_IOPORT_INDEX
459   mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
460   out  dx, ax
461   mov  dx, # VBE_DISPI_IOPORT_DATA
462   in   ax, dx
463   pop  dx
464   ret
465 
466 vga_set_virt_width:
467   push ax
468   push bx
469   push dx
470   mov  bx, ax
471   call dispi_get_bpp
472   cmp  al, #0x04
473   ja   set_width_svga
474   shr  bx, #1
475 set_width_svga:
476   shr  bx, #3
477   mov  dx, # VGAREG_VGA_CRTC_ADDRESS
478   mov  ah, bl
479   mov  al, #0x13
480   out  dx, ax
481   pop  dx
482   pop  bx
483   pop  ax
484   ret
485 
486 dispi_set_virt_width:
487   call vga_set_virt_width
488   push dx
489   push ax
490   mov  dx, # VBE_DISPI_IOPORT_INDEX
491   mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
492   out  dx, ax
493   pop  ax
494   mov  dx, # VBE_DISPI_IOPORT_DATA
495   out  dx, ax
496   pop  dx
497   ret
498 
499 dispi_get_virt_width:
500   push dx
501   mov  dx, # VBE_DISPI_IOPORT_INDEX
502   mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
503   out  dx, ax
504   mov  dx, # VBE_DISPI_IOPORT_DATA
505   in   ax, dx
506   pop  dx
507   ret
508 
509 dispi_get_virt_height:
510   push dx
511   mov  dx, # VBE_DISPI_IOPORT_INDEX
512   mov  ax, # VBE_DISPI_INDEX_VIRT_HEIGHT
513   out  dx, ax
514   mov  dx, # VBE_DISPI_IOPORT_DATA
515   in   ax, dx
516   pop  dx
517   ret
518 
519 _vga_compat_setup:
520   push ax
521   push dx
522 
523   ; set CRT X resolution
524   mov  dx, # VBE_DISPI_IOPORT_INDEX
525   mov  ax, # VBE_DISPI_INDEX_XRES
526   out  dx, ax
527   mov  dx, # VBE_DISPI_IOPORT_DATA
528   in   ax, dx
529   push ax
530   mov  dx, # VGAREG_VGA_CRTC_ADDRESS
531   mov  ax, #0x0011
532   out  dx, ax
533   pop  ax
534   push ax
535   shr  ax, #3
536   dec  ax
537   mov  ah, al
538   mov  al, #0x01
539   out  dx, ax
540   pop  ax
541   call vga_set_virt_width
542 
543   ; set CRT Y resolution
544   mov  dx, # VBE_DISPI_IOPORT_INDEX
545   mov  ax, # VBE_DISPI_INDEX_YRES
546   out  dx, ax
547   mov  dx, # VBE_DISPI_IOPORT_DATA
548   in   ax, dx
549   dec  ax
550   push ax
551   mov  dx, # VGAREG_VGA_CRTC_ADDRESS
552   mov  ah, al
553   mov  al, #0x12
554   out  dx, ax
555   pop  ax
556   mov  al, #0x07
557   out  dx, al
558   inc  dx
559   in   al, dx
560   and  al, #0xbd
561   test ah, #0x01
562   jz   bit8_clear
563   or   al, #0x02
564 bit8_clear:
565   test ah, #0x02
566   jz   bit9_clear
567   or   al, #0x40
568 bit9_clear:
569   out  dx, al
570 
571   ; other settings
572   mov  dx, # VGAREG_VGA_CRTC_ADDRESS
573   mov  ax, #0x0009
574   out  dx, ax
575   mov  al, #0x17
576   out  dx, al
577   mov  dx, # VGAREG_VGA_CRTC_DATA
578   in   al, dx
579   or   al, #0x03
580   out  dx, al
581   mov  dx, # VGAREG_ACTL_RESET
582   in   al, dx
583   mov  dx, # VGAREG_ACTL_ADDRESS
584   mov  al, #0x10
585   out  dx, al
586   mov  dx, # VGAREG_ACTL_READ_DATA
587   in   al, dx
588   or   al, #0x01
589   mov  dx, # VGAREG_ACTL_ADDRESS
590   out  dx, al
591   mov  al, #0x20
592   out  dx, al
593   mov  dx, # VGAREG_GRDC_ADDRESS
594   mov  ax, #0x0506
595   out  dx, ax
596   mov  dx, # VGAREG_SEQU_ADDRESS
597   mov  ax, #0x0f02
598   out  dx, ax
599 
600   ; settings for >= 8bpp
601   mov  dx, # VBE_DISPI_IOPORT_INDEX
602   mov  ax, # VBE_DISPI_INDEX_BPP
603   out  dx, ax
604   mov  dx, # VBE_DISPI_IOPORT_DATA
605   in   ax, dx
606   cmp  al, #0x08
607   jb   vga_compat_end
608   mov  dx, # VGAREG_VGA_CRTC_ADDRESS
609   mov  al, #0x14
610   out  dx, al
611   mov  dx, # VGAREG_VGA_CRTC_DATA
612   in   al, dx
613   or   al, #0x40
614   out  dx, al
615   mov  dx, # VGAREG_ACTL_RESET
616   in   al, dx
617   mov  dx, # VGAREG_ACTL_ADDRESS
618   mov  al, #0x10
619   out  dx, al
620   mov  dx, # VGAREG_ACTL_READ_DATA
621   in   al, dx
622   or   al, #0x40
623   mov  dx, # VGAREG_ACTL_ADDRESS
624   out  dx, al
625   mov  al, #0x20
626   out  dx, al
627   mov  dx, # VGAREG_SEQU_ADDRESS
628   mov  al, #0x04
629   out  dx, al
630   mov  dx, # VGAREG_SEQU_DATA
631   in   al, dx
632   or   al, #0x08
633   out  dx, al
634   mov  dx, # VGAREG_GRDC_ADDRESS
635   mov  al, #0x05
636   out  dx, al
637   mov  dx, # VGAREG_GRDC_DATA
638   in   al, dx
639   and  al, #0x9f
640   or   al, #0x40
641   out  dx, al
642 
643 vga_compat_end:
644   pop  dx
645   pop  ax
646 ASM_END
647 
648 
649 // ModeInfo helper function
650 static ModeInfoListItem* mode_info_find_mode(mode, using_lfb)
651   Bit16u mode; Boolean using_lfb;
652 {
653   ModeInfoListItem  *cur_info=&mode_info_list;
654 
655   while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST)
656   {
657     if (cur_info->mode == mode)
658     {
659       if (!using_lfb)
660       {
661         return cur_info;
662       }
663       else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
664       {
665         return cur_info;
666       }
667       else
668       {
669         cur_info++;
670       }
671     }
672     else
673     {
674       cur_info++;
675     }
676   }
677 
678   return 0;
679 }
680 
681 ASM_START
682 
683 ; Has VBE display - Returns true if VBE display detected
684 
685 _vbe_has_vbe_display:
686   push ds
687   push bx
688   mov  ax, # BIOSMEM_SEG
689   mov  ds, ax
690   mov  bx, # BIOSMEM_VBE_FLAG
691   mov  al, [bx]
692   and  al, #0x01
693   xor  ah, ah
694   pop  bx
695   pop  ds
696   ret
697 
698 ; VBE Init - Initialise the Vesa Bios Extension Code
699 ; This function does a sanity check on the host side display code interface.
700 
701 vbe_init:
702   mov  ax, # VBE_DISPI_ID0
703   call dispi_set_id
704   call dispi_get_id
705   cmp  ax, # VBE_DISPI_ID0
706   jne  no_vbe_interface
707   push ds
708   push bx
709   mov  ax, # BIOSMEM_SEG
710   mov  ds, ax
711   mov  bx, # BIOSMEM_VBE_FLAG
712   mov  al, #0x01
713   mov  [bx], al
714   pop  bx
715   pop  ds
716   mov  ax, # VBE_DISPI_ID5
717   call dispi_set_id
718 no_vbe_interface:
719 #if defined(USE_BX_INFO) || defined(DEBUG)
720   mov  bx, #msg_vbe_init
721   push bx
722   call _printf
723   inc  sp
724   inc  sp
725 #endif
726   ret
727 
728 ; VBE Display Info - Display information on screen about the VBE
729 
730 vbe_display_info:
731   call _vbe_has_vbe_display
732   test ax, ax
733   jz   no_vbe_flag
734   mov  ax, #0xc000
735   mov  ds, ax
736   mov  si, #_vbebios_info_string
737   jmp  _display_string
738 no_vbe_flag:
739   mov  ax, #0xc000
740   mov  ds, ax
741   mov  si, #_no_vbebios_info_string
742   jmp  _display_string
743 
744 ; helper function for memory size calculation
745 
746 lmulul:
747   and eax, #0x0000FFFF
748   shl ebx, #16
749   or  eax, ebx
750   SEG SS
751   mul eax, dword ptr [di]
752   mov ebx, eax
753   shr ebx, #16
754   ret
755 ASM_END
756 
757 /** Function 00h - Return VBE Controller Information
758  *
759  * Input:
760  *              AX      = 4F00h
761  *              ES:DI   = Pointer to buffer in which to place VbeInfoBlock structure
762  *                        (VbeSignature should be VBE2 when VBE 2.0 information is desired and
763  *                        the info block is 512 bytes in size)
764  * Output:
765  *              AX      = VBE Return Status
766  *
767  */
768 void vbe_biosfn_return_controller_information(AX, ES, DI)
769 Bit16u *AX;Bit16u ES;Bit16u DI;
770 {
771         Bit16u            ss=get_SS();
772         VbeInfoBlock      vbe_info_block;
773         Bit16u            status;
774         Bit16u            result;
775         Bit16u            vbe2_info;
776         Bit16u            cur_mode=0;
777         Bit16u            cur_ptr=34;
778         Bit16u            size_64k;
779         ModeInfoListItem  *cur_info=&mode_info_list;
780 
781         status = read_word(ss, AX);
782 
783 #ifdef DEBUG
784         printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status);
785 #endif
786 
787         vbe2_info = 0;
788 #ifdef VBE2_NO_VESA_CHECK
789 #else
790         // get vbe_info_block into local variable
791         memcpyb(ss, &vbe_info_block, ES, DI, sizeof(vbe_info_block));
792 
793         // check for VBE2 signature
794         if (((vbe_info_block.VbeSignature[0] == 'V') &&
795              (vbe_info_block.VbeSignature[1] == 'B') &&
796              (vbe_info_block.VbeSignature[2] == 'E') &&
797              (vbe_info_block.VbeSignature[3] == '2')) ||
798 
799             ((vbe_info_block.VbeSignature[0] == 'V') &&
800              (vbe_info_block.VbeSignature[1] == 'E') &&
801              (vbe_info_block.VbeSignature[2] == 'S') &&
802              (vbe_info_block.VbeSignature[3] == 'A')) )
803         {
804                 vbe2_info = 1;
805 #ifdef DEBUG
806                 printf("VBE correct VESA/VBE2 signature found\n");
807 #endif
808         }
809 #endif
810 
811         // VBE Signature
812         vbe_info_block.VbeSignature[0] = 'V';
813         vbe_info_block.VbeSignature[1] = 'E';
814         vbe_info_block.VbeSignature[2] = 'S';
815         vbe_info_block.VbeSignature[3] = 'A';
816 
817         // VBE Version supported
818         vbe_info_block.VbeVersion = 0x0200;
819 
820         // OEM String
821         vbe_info_block.OemStringPtr_Seg = 0xc000;
822         vbe_info_block.OemStringPtr_Off = &vbebios_copyright;
823 
824         // Capabilities
825         vbe_info_block.Capabilities[0] = VBE_CAPABILITY_8BIT_DAC;
826         vbe_info_block.Capabilities[1] = 0;
827         vbe_info_block.Capabilities[2] = 0;
828         vbe_info_block.Capabilities[3] = 0;
829 
830         // VBE Video Mode Pointer (dynamicly generated from the mode_info_list)
831         vbe_info_block.VideoModePtr_Seg= ES ;
832         vbe_info_block.VideoModePtr_Off= DI + 34;
833 
834         // VBE Total Memory (in 64k blocks)
835         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
836         vbe_info_block.TotalMemory = inw(VBE_DISPI_IOPORT_DATA);
837 
838         if (vbe2_info)
839         {
840                 // OEM Stuff
841                 vbe_info_block.OemSoftwareRev = VBE_OEM_SOFTWARE_REV;
842                 vbe_info_block.OemVendorNamePtr_Seg = 0xc000;
843                 vbe_info_block.OemVendorNamePtr_Off = &vbebios_vendor_name;
844                 vbe_info_block.OemProductNamePtr_Seg = 0xc000;
845                 vbe_info_block.OemProductNamePtr_Off = &vbebios_product_name;
846                 vbe_info_block.OemProductRevPtr_Seg = 0xc000;
847                 vbe_info_block.OemProductRevPtr_Off = &vbebios_product_revision;
848 
849                 // copy updates in vbe_info_block back
850                 memcpyb(ES, DI, ss, &vbe_info_block, sizeof(vbe_info_block));
851         }
852         else
853         {
854                 // copy updates in vbe_info_block back (VBE 1.x compatibility)
855                 memcpyb(ES, DI, ss, &vbe_info_block, 256);
856         }
857 
858         do
859         {
860                 size_64k = (Bit16u)((Bit32u)cur_info->info.XResolution * cur_info->info.XResolution * cur_info->info.BitsPerPixel) >> 19;
861 
862                 if ((cur_info->info.XResolution <= dispi_get_max_xres()) &&
863                     (cur_info->info.BitsPerPixel <= dispi_get_max_bpp()) &&
864                     (size_64k <= vbe_info_block.TotalMemory)) {
865 #ifdef DEBUG
866                   printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode);
867 #endif
868                   write_word(ES, DI + cur_ptr, cur_info->mode);
869                   cur_mode++;
870                   cur_ptr+=2;
871                 } else {
872 #ifdef DEBUG
873                   printf("VBE mode %x (xres=%x / bpp=%02x) not supported \n", cur_info->mode,cur_info->info.XResolution,cur_info->info.BitsPerPixel);
874 #endif
875                 }
876                 cur_info++;
877         } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST);
878 
879         // Add vesa mode list terminator
880         write_word(ES, DI + cur_ptr, cur_info->mode);
881 
882         result = 0x4f;
883 
884         write_word(ss, AX, result);
885 }
886 
887 
888 /** Function 01h - Return VBE Mode Information
889  *
890  * Input:
891  *              AX      = 4F01h
892  *              CX      = Mode Number
893  *              ES:DI   = Pointer to buffer in which to place ModeInfoBlock structure
894  * Output:
895  *              AX      = VBE Return Status
896  *
897  */
vbe_biosfn_return_mode_information(AX,CX,ES,DI)898 void vbe_biosfn_return_mode_information(AX, CX, ES, DI)
899 Bit16u *AX;Bit16u CX; Bit16u ES;Bit16u DI;
900 {
901         Bit16u            result=0x0100;
902         Bit16u            ss=get_SS();
903         ModeInfoBlock     info;
904         ModeInfoListItem  *cur_info;
905         Boolean           using_lfb;
906         Bit16u            lfb_addr;
907 
908 #ifdef DEBUG
909         printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX);
910 #endif
911 
912         using_lfb=((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
913 
914         CX = (CX & 0x1ff);
915 
916         cur_info = mode_info_find_mode(CX, using_lfb, &cur_info);
917 
918         if (cur_info != 0)
919         {
920 #ifdef DEBUG
921                 printf("VBE found mode %x\n",CX);
922 #endif
923                 memsetb(ss, &info, 0, sizeof(ModeInfoBlock));
924                 memcpyb(ss, &info, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact));
925                 if (using_lfb) {
926                   info.NumberOfBanks = 1;
927                 }
928                 lfb_addr = pci_get_lfb_addr(0x1234); // experimental vendor
929                 if (lfb_addr > 0) {
930                   info.PhysBasePtr = ((Bit32u)lfb_addr << 16);
931                 }
932                 if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
933                   info.WinFuncPtr = 0xC0000000UL;
934                   *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall);
935                 }
936 
937                 result = 0x4f;
938         }
939         else
940         {
941 #ifdef DEBUG
942                 printf("VBE *NOT* found mode %x\n",CX);
943 #endif
944                 result = 0x100;
945         }
946 
947         if (result == 0x4f)
948         {
949                 // copy updates in mode_info_block back
950                 memcpyb(ES, DI, ss, &info, sizeof(info));
951         }
952 
953         write_word(ss, AX, result);
954 }
955 
956 /** Function 02h - Set VBE Mode
957  *
958  * Input:
959  *              AX      = 4F02h
960  *              BX      = Desired Mode to set
961  *              ES:DI   = Pointer to CRTCInfoBlock structure
962  * Output:
963  *              AX      = VBE Return Status
964  *
965  */
vbe_biosfn_set_mode(AX,BX,ES,DI)966 void vbe_biosfn_set_mode(AX, BX, ES, DI)
967 Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI;
968 {
969         Bit16u            ss = get_SS();
970         Bit16u            result;
971         ModeInfoListItem  *cur_info;
972         Boolean           using_lfb;
973         Bit8u             no_clear;
974         Bit8u             lfb_flag;
975 
976         using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
977         lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0;
978         no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0;
979 
980         BX = (BX & 0x1ff);
981 
982         //result=read_word(ss,AX);
983 
984         // check for non vesa mode
985         if (BX<VBE_MODE_VESA_DEFINED)
986         {
987                 Bit8u   mode;
988 
989                 dispi_set_enable(VBE_DISPI_DISABLED);
990                 // call the vgabios in order to set the video mode
991                 // this allows for going back to textmode with a VBE call (some applications expect that to work)
992 
993                 mode=(BX & 0xff);
994                 biosfn_set_video_mode(mode);
995                 result = 0x4f;
996         }
997 
998         cur_info = mode_info_find_mode(BX, using_lfb, &cur_info);
999 
1000         if (cur_info != 0)
1001         {
1002 #ifdef DEBUG
1003                 printf("VBE found mode %x, setting:\n", BX);
1004                 printf("\txres%x yres%x bpp%x\n",
1005                         cur_info->info.XResolution,
1006                         cur_info->info.YResolution,
1007                         cur_info->info.BitsPerPixel);
1008 #endif
1009 
1010                 // first disable current mode (when switching between vesa modi)
1011                 dispi_set_enable(VBE_DISPI_DISABLED);
1012 
1013                 if (cur_info->info.BitsPerPixel == 4)
1014                 {
1015                   biosfn_set_video_mode(0x6a);
1016                 }
1017 
1018                 dispi_set_bpp(cur_info->info.BitsPerPixel);
1019                 dispi_set_xres(cur_info->info.XResolution);
1020                 dispi_set_yres(cur_info->info.YResolution);
1021                 dispi_set_bank(0);
1022                 dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
1023                 vga_compat_setup();
1024 
1025                 write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
1026                 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
1027 
1028                 result = 0x4f;
1029         }
1030         else
1031         {
1032 #ifdef DEBUG
1033                 printf("VBE *NOT* found mode %x\n" , BX);
1034 #endif
1035                 result = 0x100;
1036 
1037                 // FIXME: redirect non VBE modi to normal VGA bios operation
1038                 //        (switch back to VGA mode
1039                 if (BX == 3)
1040                         result = 0x4f;
1041         }
1042 
1043         write_word(ss, AX, result);
1044 }
1045 
1046 /** Function 03h - Return Current VBE Mode
1047  *
1048  * Input:
1049  *              AX      = 4F03h
1050  * Output:
1051  *              AX      = VBE Return Status
1052  *              BX      = Current VBE Mode
1053  *
1054  */
1055 ASM_START
1056 vbe_biosfn_return_current_mode:
1057   push ds
1058   mov  ax, # BIOSMEM_SEG
1059   mov  ds, ax
1060   call dispi_get_enable
1061   and  ax, # VBE_DISPI_ENABLED
1062   jz   no_vbe_mode
1063   mov  bx, # BIOSMEM_VBE_MODE
1064   mov  ax, [bx]
1065   mov  bx, ax
1066   jnz  vbe_03_ok
1067 no_vbe_mode:
1068   mov  bx, # BIOSMEM_CURRENT_MODE
1069   mov  al, [bx]
1070   mov  bl, al
1071   xor  bh, bh
1072 vbe_03_ok:
1073   mov  ax, #0x004f
1074   pop  ds
1075   ret
1076 ASM_END
1077 
1078 
1079 Bit16u vbe_biosfn_read_video_state_size()
1080 {
1081     return 9 * 2;
1082 }
1083 
vbe_biosfn_save_video_state(ES,BX)1084 void vbe_biosfn_save_video_state(ES, BX)
1085      Bit16u ES; Bit16u BX;
1086 {
1087     Bit16u enable, i;
1088 
1089     outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
1090     enable = inw(VBE_DISPI_IOPORT_DATA);
1091     write_word(ES, BX, enable);
1092     BX += 2;
1093     if (!(enable & VBE_DISPI_ENABLED))
1094         return;
1095     for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
1096         if (i != VBE_DISPI_INDEX_ENABLE) {
1097             outw(VBE_DISPI_IOPORT_INDEX, i);
1098             write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
1099             BX += 2;
1100         }
1101     }
1102 }
1103 
1104 
vbe_biosfn_restore_video_state(ES,BX)1105 void vbe_biosfn_restore_video_state(ES, BX)
1106      Bit16u ES; Bit16u BX;
1107 {
1108     Bit16u enable, i;
1109 
1110     enable = read_word(ES, BX);
1111     BX += 2;
1112 
1113     if (!(enable & VBE_DISPI_ENABLED)) {
1114         outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
1115         outw(VBE_DISPI_IOPORT_DATA, enable);
1116     } else {
1117         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1118         outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1119         BX += 2;
1120         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1121         outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1122         BX += 2;
1123         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1124         outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1125         BX += 2;
1126         outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
1127         outw(VBE_DISPI_IOPORT_DATA, enable);
1128 
1129         for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
1130             outw(VBE_DISPI_IOPORT_INDEX, i);
1131             outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1132             BX += 2;
1133         }
1134     }
1135 }
1136 
1137 /** Function 04h - Save/Restore State
1138  *
1139  * Input:
1140  *              AX      = 4F04h
1141  *              DL      = 00h Return Save/Restore State buffer size
1142  *                        01h Save State
1143  *                        02h Restore State
1144  *              CX      = Requested states
1145  *              ES:BX   = Pointer to buffer (if DL <> 00h)
1146  * Output:
1147  *              AX      = VBE Return Status
1148  *              BX      = Number of 64-byte blocks to hold the state buffer (if DL=00h)
1149  *
1150  */
vbe_biosfn_save_restore_state(AX,CX,DX,ES,BX)1151 void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX)
1152 Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX;
1153 {
1154     Bit16u ss=get_SS();
1155     Bit16u result, val;
1156 
1157     result = 0x4f;
1158     switch(GET_DL()) {
1159     case 0x00:
1160         val = biosfn_read_video_state_size2(CX);
1161 #ifdef DEBUG
1162         printf("VGA state size=%x\n", val);
1163 #endif
1164         if (CX & 8)
1165             val += vbe_biosfn_read_video_state_size();
1166         write_word(ss, BX, val);
1167         break;
1168     case 0x01:
1169         val = read_word(ss, BX);
1170         val = biosfn_save_video_state(CX, ES, val);
1171 #ifdef DEBUG
1172         printf("VGA save_state offset=%x\n", val);
1173 #endif
1174         if (CX & 8)
1175             vbe_biosfn_save_video_state(ES, val);
1176         break;
1177     case 0x02:
1178         val = read_word(ss, BX);
1179         val = biosfn_restore_video_state(CX, ES, val);
1180 #ifdef DEBUG
1181         printf("VGA restore_state offset=%x\n", val);
1182 #endif
1183         if (CX & 8)
1184             vbe_biosfn_restore_video_state(ES, val);
1185         break;
1186     default:
1187         // function failed
1188         result = 0x100;
1189         break;
1190     }
1191     write_word(ss, AX, result);
1192 }
1193 
1194 /** Function 05h - Display Window Control
1195  *
1196  * Input:
1197  *              AX      = 4F05h
1198  *     (16-bit) BH      = 00h Set memory window
1199  *                      = 01h Get memory window
1200  *              BL      = Window number
1201  *                      = 00h Window A
1202  *                      = 01h Window B
1203  *              DX      = Window number in video memory in window
1204  *                        granularity units (Set Memory Window only)
1205  * Note:
1206  *              If this function is called while in a linear frame buffer mode,
1207  *              this function must fail with completion code AH=03h
1208  *
1209  * Output:
1210  *              AX      = VBE Return Status
1211  *              DX      = Window number in window granularity units
1212  *                        (Get Memory Window only)
1213  */
1214 ASM_START
1215 vbe_biosfn_display_window_control:
1216   cmp  bl, #0x00
1217   jne  vbe_05_failed
1218   cmp  bh, #0x01
1219   je   get_display_window
1220   jb   set_display_window
1221   mov  ax, #0x0100
1222   ret
1223 set_display_window:
1224   mov  ax, dx
1225   call _dispi_set_bank
1226   call dispi_get_bank
1227   cmp  ax, dx
1228   jne  vbe_05_failed
1229   mov  ax, #0x004f
1230   ret
1231 get_display_window:
1232   call dispi_get_bank
1233   mov  dx, ax
1234   mov  ax, #0x004f
1235   ret
1236 vbe_05_failed:
1237   mov  ax, #0x014f
1238   ret
1239 ASM_END
1240 
1241 
1242 /** Function 06h - Set/Get Logical Scan Line Length
1243  *
1244  * Input:
1245  *              AX      = 4F06h
1246  *              BL      = 00h Set Scan Line Length in Pixels
1247  *                      = 01h Get Scan Line Length
1248  *                      = 02h Set Scan Line Length in Bytes
1249  *                      = 03h Get Maximum Scan Line Length
1250  *              CX      = If BL=00h Desired Width in Pixels
1251  *                        If BL=02h Desired Width in Bytes
1252  *                        (Ignored for Get Functions)
1253  *
1254  * Output:
1255  *              AX      = VBE Return Status
1256  *              BX      = Bytes Per Scan Line
1257  *              CX      = Actual Pixels Per Scan Line
1258  *                        (truncated to nearest complete pixel)
1259  *              DX      = Maximum Number of Scan Lines
1260  */
1261 ASM_START
1262 vbe_biosfn_set_get_logical_scan_line_length:
1263   mov  ax, cx
1264   cmp  bl, #0x01
1265   je   get_logical_scan_line_length
1266   cmp  bl, #0x02
1267   je   set_logical_scan_line_bytes
1268   jb   set_logical_scan_line_pixels
1269   mov  ax, #0x0100
1270   ret
1271 set_logical_scan_line_bytes:
1272   push ax
1273   call dispi_get_bpp
1274   xor  bh, bh
1275   mov  bl, ah
1276   or   bl, bl
1277   jnz  no_4bpp_1
1278   shl  ax, #3
1279   mov  bl, #1
1280 no_4bpp_1:
1281   xor  dx, dx
1282   pop  ax
1283   div  bx
1284 set_logical_scan_line_pixels:
1285   call dispi_set_virt_width
1286 get_logical_scan_line_length:
1287   call dispi_get_bpp
1288   xor  bh, bh
1289   mov  bl, ah
1290   call dispi_get_virt_width
1291   mov  cx, ax
1292   or   bl, bl
1293   jnz  no_4bpp_2
1294   shr  ax, #3
1295   mov  bl, #1
1296 no_4bpp_2:
1297   mul  bx
1298   mov  bx, ax
1299   call dispi_get_virt_height
1300   mov  dx, ax
1301   mov  ax, #0x004f
1302   ret
1303 ASM_END
1304 
1305 
1306 /** Function 07h - Set/Get Display Start
1307  *
1308  * Input(16-bit):
1309  *              AX      = 4F07h
1310  *              BH      = 00h Reserved and must be 00h
1311  *              BL      = 00h Set Display Start
1312  *                      = 01h Get Display Start
1313  *                      = 02h Schedule Display Start (Alternate)
1314  *                      = 03h Schedule Stereoscopic Display Start
1315  *                      = 04h Get Scheduled Display Start Status
1316  *                      = 05h Enable Stereoscopic Mode
1317  *                      = 06h Disable Stereoscopic Mode
1318  *                      = 80h Set Display Start during Vertical Retrace
1319  *                      = 82h Set Display Start during Vertical Retrace (Alternate)
1320  *                      = 83h Set Stereoscopic Display Start during Vertical Retrace
1321  *              ECX     = If BL=02h/82h Display Start Address in bytes
1322  *                        If BL=03h/83h Left Image Start Address in bytes
1323  *              EDX     = If BL=03h/83h Right Image Start Address in bytes
1324  *              CX      = If BL=00h/80h First Displayed Pixel In Scan Line
1325  *              DX      = If BL=00h/80h First Displayed Scan Line
1326  *
1327  * Output:
1328  *              AX      = VBE Return Status
1329  *              BH      = If BL=01h Reserved and will be 0
1330  *              CX      = If BL=01h First Displayed Pixel In Scan Line
1331  *                        If BL=04h 0 if flip has not occurred, not 0 if it has
1332  *              DX      = If BL=01h First Displayed Scan Line
1333  *
1334  * Input(32-bit):
1335  *              BH      = 00h Reserved and must be 00h
1336  *              BL      = 00h Set Display Start
1337  *                      = 80h Set Display Start during Vertical Retrace
1338  *              CX      = Bits 0-15 of display start address
1339  *              DX      = Bits 16-31 of display start address
1340  *              ES      = Selector for memory mapped registers
1341  */
1342 ASM_START
1343 vbe_biosfn_set_get_display_start:
1344   cmp  bl, #0x80
1345   je   set_display_start
1346   cmp  bl, #0x01
1347   je   get_display_start
1348   jb   set_display_start
1349   mov  ax, #0x0100
1350   ret
1351 set_display_start:
1352   mov  ax, cx
1353   call dispi_set_x_offset
1354   mov  ax, dx
1355   call dispi_set_y_offset
1356   mov  ax, #0x004f
1357   ret
1358 get_display_start:
1359   call dispi_get_x_offset
1360   mov  cx, ax
1361   call dispi_get_y_offset
1362   mov  dx, ax
1363   xor  bh, bh
1364   mov  ax, #0x004f
1365   ret
1366 ASM_END
1367 
1368 
1369 /** Function 08h - Set/Get Dac Palette Format
1370  *
1371  * Input:
1372  *              AX      = 4F08h
1373  *              BL      = 00h set DAC palette width
1374  *                      = 01h get DAC palette width
1375  *              BH      = If BL=00h: desired number of bits per primary color
1376  * Output:
1377  *              AX      = VBE Return Status
1378  *              BH      = current number of bits per primary color (06h = standard VGA)
1379  */
1380 ASM_START
1381 vbe_biosfn_set_get_dac_palette_format:
1382   cmp  bl, #0x01
1383   je   get_dac_palette_format
1384   jb   set_dac_palette_format
1385   mov  ax, #0x0100
1386   ret
1387 set_dac_palette_format:
1388   call dispi_get_enable
1389   cmp  bh, #0x06
1390   je   set_normal_dac
1391   cmp  bh, #0x08
1392   jne  vbe_08_unsupported
1393   or   ax, # VBE_DISPI_8BIT_DAC
1394   jnz  set_dac_mode
1395 set_normal_dac:
1396   and  ax, #~ VBE_DISPI_8BIT_DAC
1397 set_dac_mode:
1398   call _dispi_set_enable
1399 get_dac_palette_format:
1400   mov  bh, #0x06
1401   call dispi_get_enable
1402   and  ax, # VBE_DISPI_8BIT_DAC
1403   jz   vbe_08_ok
1404   mov  bh, #0x08
1405 vbe_08_ok:
1406   mov  ax, #0x004f
1407   ret
1408 vbe_08_unsupported:
1409   mov  ax, #0x014f
1410   ret
1411 ASM_END
1412 
1413 
1414 /** Function 09h - Set/Get Palette Data
1415  *
1416  * Input:
1417  *              AX      = 4F09h
1418  * Output:
1419  *              AX      = VBE Return Status
1420  *
1421  * FIXME: incomplete API description, Input & Output
1422  */
1423 void vbe_biosfn_set_get_palette_data(AX)
1424 {
1425 }
1426 
1427 /** Function 0Ah - Return VBE Protected Mode Interface
1428  * Input:    AX   = 4F0Ah   VBE 2.0 Protected Mode Interface
1429  *           BL   = 00h          Return protected mode table
1430  *
1431  *
1432  * Output:   AX   =         Status
1433  *           ES   =         Real Mode Segment of Table
1434  *           DI   =         Offset of Table
1435  *           CX   =         Length of Table including protected mode code
1436  *                          (for copying purposes)
1437  */
1438 ASM_START
1439 vbe_biosfn_return_protected_mode_interface:
1440   test bl, bl
1441   jnz _fail
1442   mov di, #0xc000
1443   mov es, di
1444   mov di, # vesa_pm_start
1445   mov cx, # vesa_pm_end
1446   sub cx, di
1447   mov ax, #0x004f
1448   ret
1449 _fail:
1450   mov ax, #0x014f
1451   ret
1452 ASM_END
1453