2 This file contains implementation of VESA library which is based on
3 LRMI (Linux real-mode interface).
4 So it's not an emulator - it calls real int 10h handler under Linux.
5 Note: VESA is available only on x86 systems.
6 You can redistribute this file under terms and conditions
7 of GNU General Public licence v2.
8 Written by Nick Kurshev <nickols_k@mail.ru>
11 #include <../config.h>
21 #include <sys/types.h>
27 static struct VesaProtModeInterface vbe_pm_info
;
28 static struct VesaModeInfoBlock curr_mode_info
;
30 static inline int VERR(const void *p
)
38 :"m"(*(unsigned char *)p
)
44 static inline int VERW(const void *p
)
52 :"m"(*(unsigned char *)p
)
58 #define HAVE_VERBOSE_VAR 1
60 #ifdef HAVE_VERBOSE_VAR
63 static void __dump_regs(struct LRMI_regs
*r
)
65 printf("vbelib: eax=%08lXh ebx=%08lXh ecx=%08lXh edx=%08lXh\n"
66 "vbelib: edi=%08lXh esi=%08lXh ebp=%08lXh esp=%08lXh\n"
67 "vbelib: ds=%04Xh es=%04Xh ss=%04Xh cs:ip=%04X:%04X\n"
68 "vbelib: fs=%04Xh gs=%04Xh ss:sp=%04X:%04X flags=%04X\n"
69 ,(unsigned long)r
->eax
,(unsigned long)r
->ebx
,(unsigned long)r
->ecx
,(unsigned long)r
->edx
70 ,(unsigned long)r
->edi
,(unsigned long)r
->esi
,(unsigned long)r
->ebp
,(unsigned long)r
->reserved
71 ,r
->ds
,r
->es
,r
->ss
,r
->cs
,r
->ip
72 ,r
->fs
,r
->gs
,r
->ss
,r
->sp
,r
->flags
);
75 static inline int VBE_LRMI_int(int int_no
, struct LRMI_regs
*r
)
80 printf("vbelib: registers before int %02X\n",int_no
);
83 retval
= LRMI_int(int_no
,r
);
86 printf("vbelib: Interrupt handler returns: %X\n",retval
);
87 printf("vbelib: registers after int %02X\n",int_no
);
93 #define VBE_LRMI_int(int_no,regs) (VBE_LRMI_int(int_no,regs))
96 static FILE *my_stdin
;
97 static FILE *my_stdout
;
98 static FILE *my_stderr
;
100 static void __set_cursor_type(FILE *stdout_fd
,int cursor_on
)
102 fprintf(stdout_fd
,"\033[?25%c",cursor_on
?'h':'l');
105 /* TODO: do it only on LCD or DFP. We should extract such info from DDC */
106 static void hide_terminal_output( void )
108 my_stdin
= fopen(ttyname(fileno(stdin
)),"r");
109 my_stdout
= fopen(ttyname(fileno(stdout
)),"w");
110 my_stderr
= fopen(ttyname(fileno(stderr
)),"w");
111 __set_cursor_type(stdout
,0);
112 /*if(isatty(fileno(stdin ))) stdin =freopen("/dev/null","r",stdin );*/
113 if(isatty(fileno(stdout
))) stdout
=freopen("/dev/null","w",stdout
);
114 if(isatty(fileno(stderr
))) stderr
=freopen("/dev/null","w",stderr
);
117 static unsigned hh_int_10_seg
;
120 the list of supported video modes is stored in the reserved portion of
121 the SuperVGA information record by some implementations, and it may
122 thus be necessary to either copy the mode list or use a different
123 buffer for all subsequent VESA calls
125 static void *controller_info
;
128 unsigned short iopl_port
;
131 if(!LRMI_init()) return VBE_VM86_FAIL
;
132 if(!(controller_info
= LRMI_alloc_real(sizeof(struct VbeInfoBlock
)))) return VBE_OUT_OF_DOS_MEM
;
134 Allow read/write to ALL io ports
136 hh_int_10_seg
= *(unsigned short *)PhysToVirtSO(0x0000,0x0042);
137 /* Video BIOS should be at C000:0000 and above */
138 hh_int_10_seg
>>= 12;
139 if(hh_int_10_seg
< 0xC) return VBE_BROKEN_BIOS
;
142 memset(&vbe_pm_info
,0,sizeof(struct VesaProtModeInterface
));
143 retval
= vbeGetProtModeInfo(&vbe_pm_info
);
144 if(retval
!= VBE_OK
) return retval
;
146 if(vbe_pm_info
.iopl_ports
) /* Can be NULL !!!*/
147 while((iopl_port
=vbe_pm_info
.iopl_ports
[i
]) != 0xFFFF
148 && vbe_pm_info
.iopl_ports
[i
++] > 1023) ioperm(iopl_port
,1,1);
150 fd_mem
= open("/dev/mem",O_RDWR
);
151 hide_terminal_output();
155 int vbeDestroy( void )
157 if (my_stdout
) __set_cursor_type(my_stdout
,1);
159 LRMI_free_real(controller_info
);
163 /* Fixme!!! This code is compatible only with mplayer's version of lrmi*/
164 static inline int is_addr_valid(const void *p
)
166 return (p
< (const void *)0x502) ||
167 (p
>= (const void *)0x10000 && p
< (const void *)0x20000) ||
168 (p
>= (const void *)0xa0000 && p
< (const void *)0x100000);
171 static int check_str(const unsigned char *str
)
175 for(i
= 0;i
< 256;i
++)
177 if(is_addr_valid(&str
[i
]))
181 if(!str
[i
]) { null_found
= 1; break; }
190 static int check_wrd(const unsigned short *str
)
194 for(i
= 0;i
< 1024;i
++)
196 if(is_addr_valid(&str
[i
]))
200 if(str
[i
] == 0xffff) { ffff_found
= 1; break; }
209 static void print_str(unsigned char *str
)
214 for(i
= 0;i
< 256;i
++) { printf("%02X(%c) ",str
[i
],isprint(str
[i
])?str
[i
]:'.'); if(!str
[i
]) break; }
219 static void print_wrd(unsigned short *str
)
224 for(i
= 0;i
< 256;i
++) { printf("%04X ",str
[i
]); if(str
[i
] == 0xffff) break; }
229 int vbeGetControllerInfo(struct VbeInfoBlock
*data
)
233 memcpy(controller_info
,data
,sizeof(struct VbeInfoBlock
));
234 memset(&r
,0,sizeof(struct LRMI_regs
));
236 r
.es
= VirtToPhysSeg(controller_info
);
237 r
.edi
= VirtToPhysOff(controller_info
);
238 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
239 retval
= r
.eax
& 0xffff;
244 memcpy(data
,controller_info
,sizeof(struct VbeInfoBlock
));
245 fpdata
.seg
= (unsigned long)(data
->OemStringPtr
) >> 16;
246 fpdata
.off
= (unsigned long)(data
->OemStringPtr
) & 0xffff;
247 data
->OemStringPtr
= PhysToVirt(fpdata
);
248 if(!check_str(data
->OemStringPtr
)) data
->OemStringPtr
= NULL
;
249 #ifdef HAVE_VERBOSE_VAR
252 printf("vbelib: OemStringPtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemStringPtr
);
253 if(data
->OemStringPtr
) print_str(data
->OemStringPtr
);
257 fpdata
.seg
= (unsigned long)(data
->VideoModePtr
) >> 16;
258 fpdata
.off
= (unsigned long)(data
->VideoModePtr
) & 0xffff;
259 data
->VideoModePtr
= PhysToVirt(fpdata
);
260 if(!check_wrd(data
->VideoModePtr
))
262 data
->VideoModePtr
= NULL
;
263 retval
= VBE_BROKEN_BIOS
;
265 #ifdef HAVE_VERBOSE_VAR
268 printf("vbelib: VideoModePtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->VideoModePtr
);
269 if(data
->VideoModePtr
) print_wrd(data
->VideoModePtr
);
273 fpdata
.seg
= (unsigned long)(data
->OemVendorNamePtr
) >> 16;
274 fpdata
.off
= (unsigned long)(data
->OemVendorNamePtr
) & 0xffff;
275 data
->OemVendorNamePtr
= PhysToVirt(fpdata
);
276 if(!check_str(data
->OemVendorNamePtr
)) data
->OemVendorNamePtr
= NULL
;
277 #ifdef HAVE_VERBOSE_VAR
280 printf("vbelib: OemVendorNamePtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemVendorNamePtr
);
281 if(data
->OemVendorNamePtr
) print_str(data
->OemVendorNamePtr
);
285 fpdata
.seg
= (unsigned long)(data
->OemProductNamePtr
) >> 16;
286 fpdata
.off
= (unsigned long)(data
->OemProductNamePtr
) & 0xffff;
287 data
->OemProductNamePtr
= PhysToVirt(fpdata
);
288 if(!check_str(data
->OemProductNamePtr
)) data
->OemProductNamePtr
= NULL
;
289 #ifdef HAVE_VERBOSE_VAR
292 printf("vbelib: OemProductNamePtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemProductNamePtr
);
293 if(data
->OemVendorNamePtr
) print_str(data
->OemProductNamePtr
);
297 fpdata
.seg
= (unsigned long)(data
->OemProductRevPtr
) >> 16;
298 fpdata
.off
= (unsigned long)(data
->OemProductRevPtr
) & 0xffff;
299 data
->OemProductRevPtr
= PhysToVirt(fpdata
);
300 if(!check_str(data
->OemProductRevPtr
)) data
->OemProductRevPtr
= NULL
;
301 #ifdef HAVE_VERBOSE_VAR
304 printf("vbelib: OemProductRevPtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemProductRevPtr
);
305 if(data
->OemProductRevPtr
) print_str(data
->OemProductRevPtr
);
313 int vbeGetModeInfo(unsigned mode
,struct VesaModeInfoBlock
*data
)
318 if(!(rm_space
= LRMI_alloc_real(sizeof(struct VesaModeInfoBlock
)))) return VBE_OUT_OF_DOS_MEM
;
319 memset(&r
,0,sizeof(struct LRMI_regs
));
322 r
.es
= VirtToPhysSeg(rm_space
);
323 r
.edi
= VirtToPhysOff(rm_space
);
324 if(!VBE_LRMI_int(0x10,&r
))
326 LRMI_free_real(rm_space
);
327 return VBE_VM86_FAIL
;
329 retval
= r
.eax
& 0xffff;
333 memcpy(data
,rm_space
,sizeof(struct VesaModeInfoBlock
));
335 LRMI_free_real(rm_space
);
339 int vbeSetMode(unsigned mode
,struct VesaCRTCInfoBlock
*data
)
342 void *rm_space
= NULL
;
344 memset(&r
,0,sizeof(struct LRMI_regs
));
347 if(!(rm_space
= LRMI_alloc_real(sizeof(struct VesaCRTCInfoBlock
)))) return VBE_OUT_OF_DOS_MEM
;
348 r
.es
= VirtToPhysSeg(rm_space
);
349 r
.edi
= VirtToPhysOff(rm_space
);
350 memcpy(rm_space
,data
,sizeof(struct VesaCRTCInfoBlock
));
354 retval
= VBE_LRMI_int(0x10,&r
);
355 LRMI_free_real(rm_space
);
356 if(!retval
) return VBE_VM86_FAIL
;
357 retval
= r
.eax
& 0xffff;
360 /* Just info for internal use (currently in SetDiplayStart func). */
361 vbeGetModeInfo(mode
&0x1f,&curr_mode_info
);
367 int vbeGetMode(unsigned *mode
)
371 memset(&r
,0,sizeof(struct LRMI_regs
));
373 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
374 retval
= r
.eax
& 0xffff;
383 int vbeGetPixelClock(unsigned *mode
,unsigned *pixel_clock
) // in Hz
387 memset(&r
,0,sizeof(struct LRMI_regs
));
391 r
.ecx
= *pixel_clock
;
392 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
393 retval
= r
.eax
& 0xffff;
396 *pixel_clock
= r
.ecx
;
403 int vbeSaveState(void **data
)
408 memset(&r
,0,sizeof(struct LRMI_regs
));
412 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
413 retval
= r
.eax
& 0xffff;
414 if(retval
!= 0x4f) return retval
;
415 if(!(rm_space
= LRMI_alloc_real((r
.ebx
& 0xffff)*64))) return VBE_OUT_OF_DOS_MEM
;
419 r
.es
= VirtToPhysSeg(rm_space
);
420 r
.ebx
= VirtToPhysOff(rm_space
);
421 if(!VBE_LRMI_int(0x10,&r
))
423 LRMI_free_real(rm_space
);
424 return VBE_VM86_FAIL
;
426 retval
= r
.eax
& 0xffff;
429 LRMI_free_real(rm_space
);
436 int vbeRestoreState(void *data
)
440 memset(&r
,0,sizeof(struct LRMI_regs
));
444 r
.es
= VirtToPhysSeg(data
);
445 r
.ebx
= VirtToPhysOff(data
);
446 retval
= VBE_LRMI_int(0x10,&r
);
447 LRMI_free_real(data
);
448 if(!retval
) return VBE_VM86_FAIL
;
449 retval
= r
.eax
& 0xffff;
450 if(retval
== 0x4f) retval
= VBE_OK
;
454 int vbeGetWindow(unsigned *win_num
)
458 memset(&r
,0,sizeof(struct LRMI_regs
));
460 r
.ebx
= (*win_num
& 0x0f) | 0x0100;
461 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
462 retval
= r
.eax
& 0xffff;
465 *win_num
= r
.edx
& 0xffff;
471 int vbeSetWindow(unsigned win_num
,unsigned win_gran
)
474 if(vbe_pm_info
.SetWindowCall
)
476 /* Don't verbose this stuff from performance reasons */
477 /* 32-bit function call is much better of int 10h */
481 ::"a"(0x4f05),"S"(win_num
& 0x0f),"d"(win_gran
):"memory");
482 (*vbe_pm_info
.SetWindowCall
)();
483 __asm
__volatile("popl %%ebx":::"memory");
489 memset(&r
,0,sizeof(struct LRMI_regs
));
491 r
.ebx
= win_num
& 0x0f;
493 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
494 retval
= r
.eax
& 0xffff;
495 if(retval
== 0x4f) retval
= VBE_OK
;
500 int vbeGetScanLineLength(unsigned *num_pixels
,unsigned *num_bytes
)
504 memset(&r
,0,sizeof(struct LRMI_regs
));
507 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
508 retval
= r
.eax
& 0xffff;
511 if(num_bytes
) *num_bytes
= r
.ebx
& 0xffff;
512 if(num_pixels
) *num_pixels
= r
.ecx
& 0xffff;
518 int vbeGetMaxScanLines(unsigned *num_pixels
,unsigned *num_bytes
, unsigned *num_lines
)
522 memset(&r
,0,sizeof(struct LRMI_regs
));
525 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
526 retval
= r
.eax
& 0xffff;
529 if(num_bytes
) *num_bytes
= r
.ebx
& 0xffff;
530 if(num_pixels
) *num_pixels
= r
.ecx
& 0xffff;
531 if(num_lines
) *num_lines
= r
.edx
& 0xffff;
537 int vbeSetScanLineLength(unsigned num_pixels
)
541 memset(&r
,0,sizeof(struct LRMI_regs
));
545 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
546 retval
= r
.eax
& 0xffff;
547 if(retval
== 0x4f) retval
= VBE_OK
;
551 int vbeSetScanLineLengthB(unsigned num_bytes
)
555 memset(&r
,0,sizeof(struct LRMI_regs
));
559 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
560 retval
= r
.eax
& 0xffff;
561 if(retval
== 0x4f) retval
= VBE_OK
;
565 int vbeGetDisplayStart(unsigned *pixel_num
,unsigned *scan_line
)
569 memset(&r
,0,sizeof(struct LRMI_regs
));
572 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
573 retval
= r
.eax
& 0xffff;
576 if(pixel_num
) *pixel_num
= r
.ecx
& 0xffff;
577 if(scan_line
) *scan_line
= r
.edx
& 0xffff;
583 int vbeSetDisplayStart(unsigned long offset
, int vsync
)
586 if(vbe_pm_info
.SetDisplayStart
)
588 /* Don't verbose this stuff from performance reasons */
589 /* 32-bit function call is much better of int 10h */
593 ::"a"(0x4f07),"S"(vsync
? 0x80 : 0),
594 "c"((offset
>>2) & 0xffff),"d"((offset
>>18)&0xffff):"memory");
595 (*vbe_pm_info
.SetDisplayStart
)();
596 __asm
__volatile("popl %%ebx":::"memory");
602 /* Something wrong here */
604 unsigned long pixel_num
;
605 memset(&r
,0,sizeof(struct LRMI_regs
));
606 pixel_num
= offset
%(unsigned long)curr_mode_info
.BytesPerScanLine
;
607 if(pixel_num
*(unsigned long)curr_mode_info
.BytesPerScanLine
!=offset
) pixel_num
++;
609 r
.ebx
= vsync
? 0x82 : 2;
611 r
.edx
= offset
/(unsigned long)curr_mode_info
.BytesPerScanLine
;
612 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
613 retval
= r
.eax
& 0xffff;
614 if(retval
== 0x4f) retval
= VBE_OK
;
616 retval
= VBE_BROKEN_BIOS
;
621 int vbeSetScheduledDisplayStart(unsigned long offset
, int vsync
)
625 unsigned long pixel_num
;
626 memset(&r
,0,sizeof(struct LRMI_regs
));
627 pixel_num
= offset
%(unsigned long)curr_mode_info
.BytesPerScanLine
;
628 if(pixel_num
*(unsigned long)curr_mode_info
.BytesPerScanLine
!=offset
) pixel_num
++;
630 r
.ebx
= vsync
? 0x82 : 2;
632 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
633 retval
= r
.eax
& 0xffff;
634 if(retval
== 0x4f) retval
= VBE_OK
;
638 struct realVesaProtModeInterface
640 unsigned short SetWindowCall
;
641 unsigned short SetDisplayStart
;
642 unsigned short SetPaletteData
;
643 unsigned short iopl_ports
;
644 }__attribute__((packed
));
646 int vbeGetProtModeInfo(struct VesaProtModeInterface
*pm_info
)
650 unsigned info_offset
;
651 struct realVesaProtModeInterface
*rm_info
;
652 memset(&r
,0,sizeof(struct LRMI_regs
));
655 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
656 retval
= r
.eax
& 0xffff;
660 info_offset
= r
.edi
&0xffff;
661 if((r
.es
>> 12) != hh_int_10_seg
) retval
= VBE_BROKEN_BIOS
;
662 rm_info
= PhysToVirtSO(r
.es
,info_offset
);
663 pm_info
->SetWindowCall
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->SetWindowCall
);
664 if(!is_addr_valid(pm_info
->SetWindowCall
)) retval
= VBE_BROKEN_BIOS
;
665 #ifdef HAVE_VERBOSE_VAR
666 if(verbose
> 1) printf("vbelib: SetWindowCall=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->SetWindowCall
,pm_info
->SetWindowCall
);
668 pm_info
->SetDisplayStart
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->SetDisplayStart
);
669 if(!is_addr_valid(pm_info
->SetDisplayStart
)) retval
= VBE_BROKEN_BIOS
;
670 #ifdef HAVE_VERBOSE_VAR
671 if(verbose
> 1) printf("vbelib: SetDisplayStart=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->SetDisplayStart
,pm_info
->SetDisplayStart
);
673 pm_info
->SetPaletteData
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->SetPaletteData
);
674 if(!is_addr_valid(pm_info
->SetPaletteData
)) retval
= VBE_BROKEN_BIOS
;
675 #ifdef HAVE_VERBOSE_VAR
676 if(verbose
> 1) printf("vbelib: SetPaletteData=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->SetPaletteData
,pm_info
->SetPaletteData
);
678 pm_info
->iopl_ports
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->iopl_ports
);
679 if(!rm_info
->iopl_ports
) pm_info
->iopl_ports
= NULL
;
681 if(!check_wrd(pm_info
->iopl_ports
))
683 pm_info
->iopl_ports
= NULL
;
684 /* retval = VBE_BROKEN_BIOS; <- It's for broken BIOSes only */
686 #ifdef HAVE_VERBOSE_VAR
689 printf("vbelib: iopl_ports=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->iopl_ports
,pm_info
->iopl_ports
);
690 if(pm_info
->iopl_ports
) print_wrd(pm_info
->iopl_ports
);
697 /* --------- Standard VGA stuff -------------- */
698 int vbeWriteString(int x
, int y
, int attr
, char *str
)
701 void *rm_space
= NULL
;
703 memset(&r
,0,sizeof(struct LRMI_regs
));
705 r
.edx
= ((y
<<8)&0xff00)|(x
&0xff);
707 if(!(rm_space
= LRMI_alloc_real(r
.ecx
))) return VBE_OUT_OF_DOS_MEM
;
708 r
.es
= VirtToPhysSeg(rm_space
);
709 r
.ebp
= VirtToPhysOff(rm_space
);
710 memcpy(rm_space
,str
,r
.ecx
);
712 retval
= VBE_LRMI_int(0x10,&r
);
713 LRMI_free_real(rm_space
);
714 if(!retval
) return VBE_VM86_FAIL
;
715 retval
= r
.eax
& 0xffff;
716 if(retval
== 0x4f) retval
= VBE_OK
;
720 void * vbeMapVideoBuffer(unsigned long phys_addr
,unsigned long size
)
723 if(fd_mem
== -1) return NULL
;
724 if(verbose
> 1) printf("vbelib: vbeMapVideoBuffer(%08lX,%08lX)\n",phys_addr
,size
);
725 /* Here we don't need with MAP_FIXED and prefered address (first argument) */
726 lfb
= mmap((void *)0,size
,PROT_READ
| PROT_WRITE
,MAP_SHARED
,fd_mem
,phys_addr
);
727 return lfb
== (void *)-1 ? 0 : lfb
;
730 void vbeUnmapVideoBuffer(unsigned long linear_addr
,unsigned long size
)
732 if(verbose
> 1) printf("vbelib: vbeUnmapVideoBuffer(%08lX,%08lX)\n",linear_addr
,size
);
733 munmap((void *)linear_addr
,size
);