Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / vgabios / vbe.c
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
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
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
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  */
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 #ifdef PCI_VID
929                 lfb_addr = pci_get_lfb_addr(PCI_VID);
930 #else
931                 lfb_addr = 0;
932 #endif
933                 if (lfb_addr > 0) {
934                   info.PhysBasePtr = ((Bit32u)lfb_addr << 16);
935                 }
936                 if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
937                   info.WinFuncPtr = 0xC0000000UL;
938                   *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall);
939                 }
940
941                 result = 0x4f;
942         }
943         else
944         {
945 #ifdef DEBUG
946                 printf("VBE *NOT* found mode %x\n",CX);
947 #endif
948                 result = 0x100;
949         }
950
951         if (result == 0x4f)
952         {
953                 // copy updates in mode_info_block back
954                 memcpyb(ES, DI, ss, &info, sizeof(info));
955         }
956
957         write_word(ss, AX, result);
958 }
959
960 /** Function 02h - Set VBE Mode
961  * 
962  * Input:
963  *              AX      = 4F02h
964  *              BX      = Desired Mode to set
965  *              ES:DI   = Pointer to CRTCInfoBlock structure
966  * Output:
967  *              AX      = VBE Return Status
968  * 
969  */
970 void vbe_biosfn_set_mode(AX, BX, ES, DI)
971 Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI;
972 {
973         Bit16u            ss = get_SS();
974         Bit16u            result;
975         ModeInfoListItem  *cur_info;
976         Boolean           using_lfb;
977         Bit8u             no_clear;
978         Bit8u             lfb_flag;
979
980         using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
981         lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0;
982         no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0;
983
984         BX = (BX & 0x1ff);
985
986         //result=read_word(ss,AX);
987
988         // check for non vesa mode
989         if (BX<VBE_MODE_VESA_DEFINED)
990         {
991                 Bit8u   mode;
992
993                 dispi_set_enable(VBE_DISPI_DISABLED);
994                 // call the vgabios in order to set the video mode
995                 // this allows for going back to textmode with a VBE call (some applications expect that to work)
996
997                 mode=(BX & 0xff);
998                 biosfn_set_video_mode(mode);
999                 result = 0x4f;
1000         }
1001
1002         cur_info = mode_info_find_mode(BX, using_lfb, &cur_info);
1003
1004         if (cur_info != 0)
1005         {
1006 #ifdef DEBUG
1007                 printf("VBE found mode %x, setting:\n", BX);
1008                 printf("\txres%x yres%x bpp%x\n",
1009                         cur_info->info.XResolution,
1010                         cur_info->info.YResolution,
1011                         cur_info->info.BitsPerPixel);
1012 #endif
1013
1014                 // first disable current mode (when switching between vesa modi)
1015                 dispi_set_enable(VBE_DISPI_DISABLED);
1016
1017                 if (cur_info->info.BitsPerPixel == 4)
1018                 {
1019                   biosfn_set_video_mode(0x6a);
1020                 }
1021
1022                 dispi_set_bpp(cur_info->info.BitsPerPixel);
1023                 dispi_set_xres(cur_info->info.XResolution);
1024                 dispi_set_yres(cur_info->info.YResolution);
1025                 dispi_set_bank(0);
1026                 dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
1027                 vga_compat_setup();
1028
1029                 write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
1030                 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
1031
1032                 result = 0x4f;
1033         }
1034         else
1035         {
1036 #ifdef DEBUG
1037                 printf("VBE *NOT* found mode %x\n" , BX);
1038 #endif
1039                 result = 0x100;
1040
1041                 // FIXME: redirect non VBE modi to normal VGA bios operation
1042                 //        (switch back to VGA mode
1043                 if (BX == 3)
1044                         result = 0x4f;
1045         }
1046
1047         write_word(ss, AX, result);
1048 }
1049
1050 /** Function 03h - Return Current VBE Mode
1051  * 
1052  * Input:
1053  *              AX      = 4F03h
1054  * Output:
1055  *              AX      = VBE Return Status
1056  *              BX      = Current VBE Mode
1057  * 
1058  */
1059 ASM_START
1060 vbe_biosfn_return_current_mode:
1061   push ds
1062   mov  ax, # BIOSMEM_SEG
1063   mov  ds, ax
1064   call dispi_get_enable
1065   and  ax, # VBE_DISPI_ENABLED
1066   jz   no_vbe_mode
1067   mov  bx, # BIOSMEM_VBE_MODE
1068   mov  ax, [bx]
1069   mov  bx, ax
1070   jnz  vbe_03_ok
1071 no_vbe_mode:
1072   mov  bx, # BIOSMEM_CURRENT_MODE
1073   mov  al, [bx]
1074   mov  bl, al
1075   xor  bh, bh
1076 vbe_03_ok:
1077   mov  ax, #0x004f
1078   pop  ds
1079   ret
1080 ASM_END
1081
1082
1083 Bit16u vbe_biosfn_read_video_state_size()
1084 {
1085     return 9 * 2;
1086 }
1087
1088 void vbe_biosfn_save_video_state(ES, BX)
1089      Bit16u ES; Bit16u BX;
1090 {
1091     Bit16u enable, i;
1092
1093     outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
1094     enable = inw(VBE_DISPI_IOPORT_DATA);
1095     write_word(ES, BX, enable);
1096     BX += 2;
1097     if (!(enable & VBE_DISPI_ENABLED)) 
1098         return;
1099     for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
1100         if (i != VBE_DISPI_INDEX_ENABLE) {
1101             outw(VBE_DISPI_IOPORT_INDEX, i);
1102             write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
1103             BX += 2;
1104         }
1105     }
1106 }
1107
1108
1109 void vbe_biosfn_restore_video_state(ES, BX)
1110      Bit16u ES; Bit16u BX;
1111 {
1112     Bit16u enable, i;
1113
1114     enable = read_word(ES, BX);
1115     BX += 2;
1116
1117     if (!(enable & VBE_DISPI_ENABLED)) {
1118         outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
1119         outw(VBE_DISPI_IOPORT_DATA, enable);
1120     } else {
1121         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1122         outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1123         BX += 2;
1124         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1125         outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1126         BX += 2;
1127         outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1128         outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1129         BX += 2;
1130         outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
1131         outw(VBE_DISPI_IOPORT_DATA, enable);
1132
1133         for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
1134             outw(VBE_DISPI_IOPORT_INDEX, i);
1135             outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
1136             BX += 2;
1137         }
1138     }
1139 }
1140
1141 /** Function 04h - Save/Restore State
1142  * 
1143  * Input:
1144  *              AX      = 4F04h
1145  *              DL      = 00h Return Save/Restore State buffer size
1146  *                        01h Save State
1147  *                        02h Restore State
1148  *              CX      = Requested states
1149  *              ES:BX   = Pointer to buffer (if DL <> 00h)
1150  * Output:
1151  *              AX      = VBE Return Status
1152  *              BX      = Number of 64-byte blocks to hold the state buffer (if DL=00h)
1153  * 
1154  */
1155 void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX)
1156 Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX;
1157 {
1158     Bit16u ss=get_SS();
1159     Bit16u result, val;
1160
1161     result = 0x4f;
1162     switch(GET_DL()) {
1163     case 0x00:
1164         val = biosfn_read_video_state_size2(CX);
1165 #ifdef DEBUG
1166         printf("VGA state size=%x\n", val);
1167 #endif
1168         if (CX & 8)
1169             val += vbe_biosfn_read_video_state_size();
1170         write_word(ss, BX, val);
1171         break;
1172     case 0x01:
1173         val = read_word(ss, BX);
1174         val = biosfn_save_video_state(CX, ES, val);
1175 #ifdef DEBUG
1176         printf("VGA save_state offset=%x\n", val);
1177 #endif
1178         if (CX & 8)
1179             vbe_biosfn_save_video_state(ES, val);
1180         break;
1181     case 0x02:
1182         val = read_word(ss, BX);
1183         val = biosfn_restore_video_state(CX, ES, val);
1184 #ifdef DEBUG
1185         printf("VGA restore_state offset=%x\n", val);
1186 #endif
1187         if (CX & 8)
1188             vbe_biosfn_restore_video_state(ES, val);
1189         break;
1190     default:
1191         // function failed
1192         result = 0x100;
1193         break;
1194     }
1195     write_word(ss, AX, result);
1196 }
1197
1198 /** Function 05h - Display Window Control
1199  * 
1200  * Input:
1201  *              AX      = 4F05h
1202  *     (16-bit) BH      = 00h Set memory window
1203  *                      = 01h Get memory window
1204  *              BL      = Window number
1205  *                      = 00h Window A
1206  *                      = 01h Window B
1207  *              DX      = Window number in video memory in window
1208  *                        granularity units (Set Memory Window only)
1209  * Note:
1210  *              If this function is called while in a linear frame buffer mode,
1211  *              this function must fail with completion code AH=03h
1212  * 
1213  * Output:
1214  *              AX      = VBE Return Status
1215  *              DX      = Window number in window granularity units
1216  *                        (Get Memory Window only)
1217  */
1218 ASM_START
1219 vbe_biosfn_display_window_control:
1220   cmp  bl, #0x00
1221   jne  vbe_05_failed
1222   cmp  bh, #0x01
1223   je   get_display_window
1224   jb   set_display_window
1225   mov  ax, #0x0100
1226   ret
1227 set_display_window:
1228   mov  ax, dx
1229   call _dispi_set_bank
1230   call dispi_get_bank
1231   cmp  ax, dx
1232   jne  vbe_05_failed
1233   mov  ax, #0x004f
1234   ret
1235 get_display_window:
1236   call dispi_get_bank
1237   mov  dx, ax
1238   mov  ax, #0x004f
1239   ret
1240 vbe_05_failed:
1241   mov  ax, #0x014f
1242   ret
1243 ASM_END
1244
1245
1246 /** Function 06h - Set/Get Logical Scan Line Length
1247  *
1248  * Input:
1249  *              AX      = 4F06h
1250  *              BL      = 00h Set Scan Line Length in Pixels
1251  *                      = 01h Get Scan Line Length
1252  *                      = 02h Set Scan Line Length in Bytes
1253  *                      = 03h Get Maximum Scan Line Length
1254  *              CX      = If BL=00h Desired Width in Pixels
1255  *                        If BL=02h Desired Width in Bytes
1256  *                        (Ignored for Get Functions)
1257  * 
1258  * Output: 
1259  *              AX      = VBE Return Status
1260  *              BX      = Bytes Per Scan Line
1261  *              CX      = Actual Pixels Per Scan Line
1262  *                        (truncated to nearest complete pixel)
1263  *              DX      = Maximum Number of Scan Lines 
1264  */
1265 ASM_START
1266 vbe_biosfn_set_get_logical_scan_line_length:
1267   mov  ax, cx
1268   cmp  bl, #0x01
1269   je   get_logical_scan_line_length
1270   cmp  bl, #0x02
1271   je   set_logical_scan_line_bytes
1272   jb   set_logical_scan_line_pixels
1273   mov  ax, #0x0100
1274   ret
1275 set_logical_scan_line_bytes:
1276   push ax
1277   call dispi_get_bpp
1278   xor  bh, bh
1279   mov  bl, ah
1280   or   bl, bl
1281   jnz  no_4bpp_1
1282   shl  ax, #3
1283   mov  bl, #1
1284 no_4bpp_1:
1285   xor  dx, dx
1286   pop  ax
1287   div  bx
1288 set_logical_scan_line_pixels:
1289   call dispi_set_virt_width
1290 get_logical_scan_line_length:
1291   call dispi_get_bpp
1292   xor  bh, bh
1293   mov  bl, ah
1294   call dispi_get_virt_width
1295   mov  cx, ax
1296   or   bl, bl
1297   jnz  no_4bpp_2
1298   shr  ax, #3
1299   mov  bl, #1
1300 no_4bpp_2:
1301   mul  bx
1302   mov  bx, ax
1303   call dispi_get_virt_height
1304   mov  dx, ax
1305   mov  ax, #0x004f
1306   ret
1307 ASM_END
1308
1309
1310 /** Function 07h - Set/Get Display Start
1311  * 
1312  * Input(16-bit):
1313  *              AX      = 4F07h
1314  *              BH      = 00h Reserved and must be 00h
1315  *              BL      = 00h Set Display Start
1316  *                      = 01h Get Display Start
1317  *                      = 02h Schedule Display Start (Alternate)
1318  *                      = 03h Schedule Stereoscopic Display Start
1319  *                      = 04h Get Scheduled Display Start Status
1320  *                      = 05h Enable Stereoscopic Mode
1321  *                      = 06h Disable Stereoscopic Mode
1322  *                      = 80h Set Display Start during Vertical Retrace
1323  *                      = 82h Set Display Start during Vertical Retrace (Alternate)
1324  *                      = 83h Set Stereoscopic Display Start during Vertical Retrace
1325  *              ECX     = If BL=02h/82h Display Start Address in bytes
1326  *                        If BL=03h/83h Left Image Start Address in bytes
1327  *              EDX     = If BL=03h/83h Right Image Start Address in bytes
1328  *              CX      = If BL=00h/80h First Displayed Pixel In Scan Line
1329  *              DX      = If BL=00h/80h First Displayed Scan Line
1330  *
1331  * Output:
1332  *              AX      = VBE Return Status
1333  *              BH      = If BL=01h Reserved and will be 0
1334  *              CX      = If BL=01h First Displayed Pixel In Scan Line
1335  *                        If BL=04h 0 if flip has not occurred, not 0 if it has
1336  *              DX      = If BL=01h First Displayed Scan Line
1337  *
1338  * Input(32-bit): 
1339  *              BH      = 00h Reserved and must be 00h
1340  *              BL      = 00h Set Display Start
1341  *                      = 80h Set Display Start during Vertical Retrace
1342  *              CX      = Bits 0-15 of display start address
1343  *              DX      = Bits 16-31 of display start address
1344  *              ES      = Selector for memory mapped registers 
1345  */
1346 ASM_START
1347 vbe_biosfn_set_get_display_start:
1348   cmp  bl, #0x80
1349   je   set_display_start
1350   cmp  bl, #0x01
1351   je   get_display_start
1352   jb   set_display_start
1353   mov  ax, #0x0100
1354   ret
1355 set_display_start:
1356   mov  ax, cx
1357   call dispi_set_x_offset
1358   mov  ax, dx
1359   call dispi_set_y_offset
1360   mov  ax, #0x004f
1361   ret
1362 get_display_start:
1363   call dispi_get_x_offset
1364   mov  cx, ax
1365   call dispi_get_y_offset
1366   mov  dx, ax
1367   xor  bh, bh
1368   mov  ax, #0x004f
1369   ret
1370 ASM_END
1371   
1372
1373 /** Function 08h - Set/Get Dac Palette Format
1374  * 
1375  * Input:
1376  *              AX      = 4F08h
1377  *              BL      = 00h set DAC palette width
1378  *                      = 01h get DAC palette width
1379  *              BH      = If BL=00h: desired number of bits per primary color
1380  * Output:
1381  *              AX      = VBE Return Status
1382  *              BH      = current number of bits per primary color (06h = standard VGA)
1383  */
1384 ASM_START
1385 vbe_biosfn_set_get_dac_palette_format:
1386   cmp  bl, #0x01
1387   je   get_dac_palette_format
1388   jb   set_dac_palette_format
1389   mov  ax, #0x0100
1390   ret
1391 set_dac_palette_format:
1392   call dispi_get_enable
1393   cmp  bh, #0x06
1394   je   set_normal_dac
1395   cmp  bh, #0x08
1396   jne  vbe_08_unsupported
1397   or   ax, # VBE_DISPI_8BIT_DAC
1398   jnz  set_dac_mode
1399 set_normal_dac:
1400   and  ax, #~ VBE_DISPI_8BIT_DAC
1401 set_dac_mode:
1402   call _dispi_set_enable
1403 get_dac_palette_format:
1404   mov  bh, #0x06
1405   call dispi_get_enable
1406   and  ax, # VBE_DISPI_8BIT_DAC
1407   jz   vbe_08_ok
1408   mov  bh, #0x08
1409 vbe_08_ok:
1410   mov  ax, #0x004f
1411   ret
1412 vbe_08_unsupported:
1413   mov  ax, #0x014f
1414   ret
1415 ASM_END
1416
1417
1418 /** Function 09h - Set/Get Palette Data
1419  * 
1420  * Input:
1421  *              AX      = 4F09h
1422  * Output:
1423  *              AX      = VBE Return Status
1424  *
1425  * FIXME: incomplete API description, Input & Output
1426  */
1427 void vbe_biosfn_set_get_palette_data(AX)
1428 {
1429 }
1430
1431 /** Function 0Ah - Return VBE Protected Mode Interface
1432  * Input:    AX   = 4F0Ah   VBE 2.0 Protected Mode Interface
1433  *           BL   = 00h          Return protected mode table
1434  *
1435  *
1436  * Output:   AX   =         Status
1437  *           ES   =         Real Mode Segment of Table
1438  *           DI   =         Offset of Table
1439  *           CX   =         Length of Table including protected mode code
1440  *                          (for copying purposes)
1441  */
1442 ASM_START
1443 vbe_biosfn_return_protected_mode_interface:
1444   test bl, bl
1445   jnz _fail
1446   mov di, #0xc000
1447   mov es, di
1448   mov di, # vesa_pm_start
1449   mov cx, # vesa_pm_end
1450   sub cx, di
1451   mov ax, #0x004f
1452   ret
1453 _fail:
1454   mov ax, #0x014f
1455   ret
1456 ASM_END