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>
17 #include <sys/types.h>
23 static struct VesaProtModeInterface vbe_pm_info
;
24 static struct VesaModeInfoBlock curr_mode_info
;
26 static inline int VERR(const void *p
)
34 :"m"(*(unsigned char *)p
)
40 static inline int VERW(const void *p
)
48 :"m"(*(unsigned char *)p
)
54 #define HAVE_VERBOSE_VAR 1
56 #ifdef HAVE_VERBOSE_VAR
59 static void __dump_regs(struct LRMI_regs
*r
)
61 printf("vbelib: eax=%08lXh ebx=%08lXh ecx=%08lXh edx=%08lXh\n"
62 "vbelib: edi=%08lXh esi=%08lXh ebp=%08lXh esp=%08lXh\n"
63 "vbelib: ds=%04Xh es=%04Xh ss=%04Xh cs:ip=%04X:%04X\n"
64 "vbelib: fs=%04Xh gs=%04Xh ss:sp=%04X:%04X flags=%04X\n"
65 ,(unsigned long)r
->eax
,(unsigned long)r
->ebx
,(unsigned long)r
->ecx
,(unsigned long)r
->edx
66 ,(unsigned long)r
->edi
,(unsigned long)r
->esi
,(unsigned long)r
->ebp
,(unsigned long)r
->reserved
67 ,r
->ds
,r
->es
,r
->ss
,r
->cs
,r
->ip
68 ,r
->fs
,r
->gs
,r
->ss
,r
->sp
,r
->flags
);
71 static inline int VBE_LRMI_int(int int_no
, struct LRMI_regs
*r
)
76 printf("vbelib: registers before int %02X\n",int_no
);
79 retval
= LRMI_int(int_no
,r
);
82 printf("vbelib: Interrupt handler returns: %X\n",retval
);
83 printf("vbelib: registers after int %02X\n",int_no
);
89 #define VBE_LRMI_int(int_no,regs) (VBE_LRMI_int(int_no,regs))
92 static FILE *my_stdin
;
93 static FILE *my_stdout
;
94 static FILE *my_stderr
;
96 static void __set_cursor_type(FILE *stdout_fd
,int cursor_on
)
98 fprintf(stdout_fd
,"\033[?25%c",cursor_on
?'h':'l');
101 /* TODO: do it only on LCD or DFP. We should extract such info from DDC */
102 static void hide_terminal_output( void )
104 my_stdin
= fopen(ttyname(fileno(stdin
)),"r");
105 my_stdout
= fopen(ttyname(fileno(stdout
)),"w");
106 my_stderr
= fopen(ttyname(fileno(stderr
)),"w");
107 __set_cursor_type(stdout
,0);
108 /*if(isatty(fileno(stdin ))) stdin =freopen("/dev/null","r",stdin );*/
109 if(isatty(fileno(stdout
))) stdout
=freopen("/dev/null","w",stdout
);
110 if(isatty(fileno(stderr
))) stderr
=freopen("/dev/null","w",stderr
);
113 static unsigned hh_int_10_seg
;
116 the list of supported video modes is stored in the reserved portion of
117 the SuperVGA information record by some implementations, and it may
118 thus be necessary to either copy the mode list or use a different
119 buffer for all subsequent VESA calls
121 static void *controller_info
;
124 unsigned short iopl_port
;
127 if(!LRMI_init()) return VBE_VM86_FAIL
;
128 if(!(controller_info
= LRMI_alloc_real(sizeof(struct VbeInfoBlock
)))) return VBE_OUT_OF_DOS_MEM
;
130 Allow read/write to ALL io ports
132 hh_int_10_seg
= *(unsigned short *)PhysToVirtSO(0x0000,0x0042);
133 /* Video BIOS should be at C000:0000 and above */
134 hh_int_10_seg
>>= 12;
135 if(hh_int_10_seg
< 0xC) return VBE_BROKEN_BIOS
;
138 memset(&vbe_pm_info
,0,sizeof(struct VesaProtModeInterface
));
139 retval
= vbeGetProtModeInfo(&vbe_pm_info
);
140 if(retval
!= VBE_OK
) return retval
;
142 if(vbe_pm_info
.iopl_ports
) /* Can be NULL !!!*/
143 while((iopl_port
=vbe_pm_info
.iopl_ports
[i
]) != 0xFFFF
144 && vbe_pm_info
.iopl_ports
[i
++] > 1023) ioperm(iopl_port
,1,1);
146 fd_mem
= open("/dev/mem",O_RDWR
);
147 hide_terminal_output();
151 int vbeDestroy( void )
153 if (my_stdout
) __set_cursor_type(my_stdout
,1);
155 LRMI_free_real(controller_info
);
159 /* Fixme!!! This code is compatible only with mplayer's version of lrmi*/
160 static inline int is_addr_valid(const void *p
)
162 return (p
< (const void *)0x502) ||
163 (p
>= (const void *)0x10000 && p
< (const void *)0x20000) ||
164 (p
>= (const void *)0xa0000 && p
< (const void *)0x100000);
167 static int check_str(const unsigned char *str
)
171 for(i
= 0;i
< 256;i
++)
173 if(is_addr_valid(&str
[i
]))
177 if(!str
[i
]) { null_found
= 1; break; }
186 static int check_wrd(const unsigned short *str
)
190 for(i
= 0;i
< 1024;i
++)
192 if(is_addr_valid(&str
[i
]))
196 if(str
[i
] == 0xffff) { ffff_found
= 1; break; }
205 static void print_str(unsigned char *str
)
210 for(i
= 0;i
< 256;i
++) { printf("%02X(%c) ",str
[i
],isprint(str
[i
])?str
[i
]:'.'); if(!str
[i
]) break; }
215 static void print_wrd(unsigned short *str
)
220 for(i
= 0;i
< 256;i
++) { printf("%04X ",str
[i
]); if(str
[i
] == 0xffff) break; }
225 int vbeGetControllerInfo(struct VbeInfoBlock
*data
)
229 memcpy(controller_info
,data
,sizeof(struct VbeInfoBlock
));
230 memset(&r
,0,sizeof(struct LRMI_regs
));
232 r
.es
= VirtToPhysSeg(controller_info
);
233 r
.edi
= VirtToPhysOff(controller_info
);
234 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
235 retval
= r
.eax
& 0xffff;
240 memcpy(data
,controller_info
,sizeof(struct VbeInfoBlock
));
241 fpdata
.seg
= (unsigned long)(data
->OemStringPtr
) >> 16;
242 fpdata
.off
= (unsigned long)(data
->OemStringPtr
) & 0xffff;
243 data
->OemStringPtr
= PhysToVirt(fpdata
);
244 if(!check_str(data
->OemStringPtr
)) data
->OemStringPtr
= NULL
;
245 #ifdef HAVE_VERBOSE_VAR
248 printf("vbelib: OemStringPtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemStringPtr
);
249 if(data
->OemStringPtr
) print_str(data
->OemStringPtr
);
253 fpdata
.seg
= (unsigned long)(data
->VideoModePtr
) >> 16;
254 fpdata
.off
= (unsigned long)(data
->VideoModePtr
) & 0xffff;
255 data
->VideoModePtr
= PhysToVirt(fpdata
);
256 if(!check_wrd(data
->VideoModePtr
))
258 data
->VideoModePtr
= NULL
;
259 retval
= VBE_BROKEN_BIOS
;
261 #ifdef HAVE_VERBOSE_VAR
264 printf("vbelib: VideoModePtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->VideoModePtr
);
265 if(data
->VideoModePtr
) print_wrd(data
->VideoModePtr
);
269 fpdata
.seg
= (unsigned long)(data
->OemVendorNamePtr
) >> 16;
270 fpdata
.off
= (unsigned long)(data
->OemVendorNamePtr
) & 0xffff;
271 data
->OemVendorNamePtr
= PhysToVirt(fpdata
);
272 if(!check_str(data
->OemVendorNamePtr
)) data
->OemVendorNamePtr
= NULL
;
273 #ifdef HAVE_VERBOSE_VAR
276 printf("vbelib: OemVendorNamePtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemVendorNamePtr
);
277 if(data
->OemVendorNamePtr
) print_str(data
->OemVendorNamePtr
);
281 fpdata
.seg
= (unsigned long)(data
->OemProductNamePtr
) >> 16;
282 fpdata
.off
= (unsigned long)(data
->OemProductNamePtr
) & 0xffff;
283 data
->OemProductNamePtr
= PhysToVirt(fpdata
);
284 if(!check_str(data
->OemProductNamePtr
)) data
->OemProductNamePtr
= NULL
;
285 #ifdef HAVE_VERBOSE_VAR
288 printf("vbelib: OemProductNamePtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemProductNamePtr
);
289 if(data
->OemVendorNamePtr
) print_str(data
->OemProductNamePtr
);
293 fpdata
.seg
= (unsigned long)(data
->OemProductRevPtr
) >> 16;
294 fpdata
.off
= (unsigned long)(data
->OemProductRevPtr
) & 0xffff;
295 data
->OemProductRevPtr
= PhysToVirt(fpdata
);
296 if(!check_str(data
->OemProductRevPtr
)) data
->OemProductRevPtr
= NULL
;
297 #ifdef HAVE_VERBOSE_VAR
300 printf("vbelib: OemProductRevPtr=%04X:%04X => %p\n",fpdata
.seg
,fpdata
.off
,data
->OemProductRevPtr
);
301 if(data
->OemProductRevPtr
) print_str(data
->OemProductRevPtr
);
309 int vbeGetModeInfo(unsigned mode
,struct VesaModeInfoBlock
*data
)
314 if(!(rm_space
= LRMI_alloc_real(sizeof(struct VesaModeInfoBlock
)))) return VBE_OUT_OF_DOS_MEM
;
315 memset(&r
,0,sizeof(struct LRMI_regs
));
318 r
.es
= VirtToPhysSeg(rm_space
);
319 r
.edi
= VirtToPhysOff(rm_space
);
320 if(!VBE_LRMI_int(0x10,&r
))
322 LRMI_free_real(rm_space
);
323 return VBE_VM86_FAIL
;
325 retval
= r
.eax
& 0xffff;
329 memcpy(data
,rm_space
,sizeof(struct VesaModeInfoBlock
));
331 LRMI_free_real(rm_space
);
335 int vbeSetMode(unsigned mode
,struct VesaCRTCInfoBlock
*data
)
338 void *rm_space
= NULL
;
340 memset(&r
,0,sizeof(struct LRMI_regs
));
343 if(!(rm_space
= LRMI_alloc_real(sizeof(struct VesaCRTCInfoBlock
)))) return VBE_OUT_OF_DOS_MEM
;
344 r
.es
= VirtToPhysSeg(rm_space
);
345 r
.edi
= VirtToPhysOff(rm_space
);
346 memcpy(rm_space
,data
,sizeof(struct VesaCRTCInfoBlock
));
350 retval
= VBE_LRMI_int(0x10,&r
);
351 LRMI_free_real(rm_space
);
352 if(!retval
) return VBE_VM86_FAIL
;
353 retval
= r
.eax
& 0xffff;
356 /* Just info for internal use (currently in SetDiplayStart func). */
357 vbeGetModeInfo(mode
&0x1f,&curr_mode_info
);
363 int vbeGetMode(unsigned *mode
)
367 memset(&r
,0,sizeof(struct LRMI_regs
));
369 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
370 retval
= r
.eax
& 0xffff;
379 int vbeGetPixelClock(unsigned *mode
,unsigned *pixel_clock
) // in Hz
383 memset(&r
,0,sizeof(struct LRMI_regs
));
387 r
.ecx
= *pixel_clock
;
388 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
389 retval
= r
.eax
& 0xffff;
392 *pixel_clock
= r
.ecx
;
399 int vbeSaveState(void **data
)
404 memset(&r
,0,sizeof(struct LRMI_regs
));
408 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
409 retval
= r
.eax
& 0xffff;
410 if(retval
!= 0x4f) return retval
;
411 if(!(rm_space
= LRMI_alloc_real((r
.ebx
& 0xffff)*64))) return VBE_OUT_OF_DOS_MEM
;
415 r
.es
= VirtToPhysSeg(rm_space
);
416 r
.ebx
= VirtToPhysOff(rm_space
);
417 if(!VBE_LRMI_int(0x10,&r
))
419 LRMI_free_real(rm_space
);
420 return VBE_VM86_FAIL
;
422 retval
= r
.eax
& 0xffff;
425 LRMI_free_real(rm_space
);
432 int vbeRestoreState(void *data
)
436 memset(&r
,0,sizeof(struct LRMI_regs
));
440 r
.es
= VirtToPhysSeg(data
);
441 r
.ebx
= VirtToPhysOff(data
);
442 retval
= VBE_LRMI_int(0x10,&r
);
443 LRMI_free_real(data
);
444 if(!retval
) return VBE_VM86_FAIL
;
445 retval
= r
.eax
& 0xffff;
446 if(retval
== 0x4f) retval
= VBE_OK
;
450 int vbeGetWindow(unsigned *win_num
)
454 memset(&r
,0,sizeof(struct LRMI_regs
));
456 r
.ebx
= (*win_num
& 0x0f) | 0x0100;
457 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
458 retval
= r
.eax
& 0xffff;
461 *win_num
= r
.edx
& 0xffff;
467 int vbeSetWindow(unsigned win_num
,unsigned win_gran
)
470 if(vbe_pm_info
.SetWindowCall
)
472 /* Don't verbose this stuff from performance reasons */
473 /* 32-bit function call is much better of int 10h */
477 ::"a"(0x4f05),"S"(win_num
& 0x0f),"d"(win_gran
):"memory");
478 (*vbe_pm_info
.SetWindowCall
)();
479 __asm
__volatile("popl %%ebx":::"memory");
485 memset(&r
,0,sizeof(struct LRMI_regs
));
487 r
.ebx
= win_num
& 0x0f;
489 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
490 retval
= r
.eax
& 0xffff;
491 if(retval
== 0x4f) retval
= VBE_OK
;
496 int vbeGetScanLineLength(unsigned *num_pixels
,unsigned *num_bytes
)
500 memset(&r
,0,sizeof(struct LRMI_regs
));
503 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
504 retval
= r
.eax
& 0xffff;
507 if(num_bytes
) *num_bytes
= r
.ebx
& 0xffff;
508 if(num_pixels
) *num_pixels
= r
.ecx
& 0xffff;
514 int vbeGetMaxScanLines(unsigned *num_pixels
,unsigned *num_bytes
, unsigned *num_lines
)
518 memset(&r
,0,sizeof(struct LRMI_regs
));
521 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
522 retval
= r
.eax
& 0xffff;
525 if(num_bytes
) *num_bytes
= r
.ebx
& 0xffff;
526 if(num_pixels
) *num_pixels
= r
.ecx
& 0xffff;
527 if(num_lines
) *num_lines
= r
.edx
& 0xffff;
533 int vbeSetScanLineLength(unsigned num_pixels
)
537 memset(&r
,0,sizeof(struct LRMI_regs
));
541 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
542 retval
= r
.eax
& 0xffff;
543 if(retval
== 0x4f) retval
= VBE_OK
;
547 int vbeSetScanLineLengthB(unsigned num_bytes
)
551 memset(&r
,0,sizeof(struct LRMI_regs
));
555 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
556 retval
= r
.eax
& 0xffff;
557 if(retval
== 0x4f) retval
= VBE_OK
;
561 int vbeGetDisplayStart(unsigned *pixel_num
,unsigned *scan_line
)
565 memset(&r
,0,sizeof(struct LRMI_regs
));
568 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
569 retval
= r
.eax
& 0xffff;
572 if(pixel_num
) *pixel_num
= r
.ecx
& 0xffff;
573 if(scan_line
) *scan_line
= r
.edx
& 0xffff;
579 int vbeSetDisplayStart(unsigned long offset
, int vsync
)
582 if(vbe_pm_info
.SetDisplayStart
)
584 /* Don't verbose this stuff from performance reasons */
585 /* 32-bit function call is much better of int 10h */
589 ::"a"(0x4f07),"S"(vsync
? 0x80 : 0),
590 "c"((offset
>>2) & 0xffff),"d"((offset
>>18)&0xffff):"memory");
591 (*vbe_pm_info
.SetDisplayStart
)();
592 __asm
__volatile("popl %%ebx":::"memory");
598 /* Something wrong here */
600 unsigned long pixel_num
;
601 memset(&r
,0,sizeof(struct LRMI_regs
));
602 pixel_num
= offset
%(unsigned long)curr_mode_info
.BytesPerScanLine
;
603 if(pixel_num
*(unsigned long)curr_mode_info
.BytesPerScanLine
!=offset
) pixel_num
++;
605 r
.ebx
= vsync
? 0x82 : 2;
607 r
.edx
= offset
/(unsigned long)curr_mode_info
.BytesPerScanLine
;
608 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
609 retval
= r
.eax
& 0xffff;
610 if(retval
== 0x4f) retval
= VBE_OK
;
612 retval
= VBE_BROKEN_BIOS
;
617 int vbeSetScheduledDisplayStart(unsigned long offset
, int vsync
)
621 unsigned long pixel_num
;
622 memset(&r
,0,sizeof(struct LRMI_regs
));
623 pixel_num
= offset
%(unsigned long)curr_mode_info
.BytesPerScanLine
;
624 if(pixel_num
*(unsigned long)curr_mode_info
.BytesPerScanLine
!=offset
) pixel_num
++;
626 r
.ebx
= vsync
? 0x82 : 2;
628 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
629 retval
= r
.eax
& 0xffff;
630 if(retval
== 0x4f) retval
= VBE_OK
;
634 struct realVesaProtModeInterface
636 unsigned short SetWindowCall
;
637 unsigned short SetDisplayStart
;
638 unsigned short SetPaletteData
;
639 unsigned short iopl_ports
;
640 }__attribute__((packed
));
642 int vbeGetProtModeInfo(struct VesaProtModeInterface
*pm_info
)
646 unsigned info_offset
;
647 struct realVesaProtModeInterface
*rm_info
;
648 memset(&r
,0,sizeof(struct LRMI_regs
));
651 if(!VBE_LRMI_int(0x10,&r
)) return VBE_VM86_FAIL
;
652 retval
= r
.eax
& 0xffff;
656 info_offset
= r
.edi
&0xffff;
657 if((r
.es
>> 12) != hh_int_10_seg
) retval
= VBE_BROKEN_BIOS
;
658 rm_info
= PhysToVirtSO(r
.es
,info_offset
);
659 pm_info
->SetWindowCall
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->SetWindowCall
);
660 if(!is_addr_valid(pm_info
->SetWindowCall
)) retval
= VBE_BROKEN_BIOS
;
661 #ifdef HAVE_VERBOSE_VAR
662 if(verbose
> 1) printf("vbelib: SetWindowCall=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->SetWindowCall
,pm_info
->SetWindowCall
);
664 pm_info
->SetDisplayStart
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->SetDisplayStart
);
665 if(!is_addr_valid(pm_info
->SetDisplayStart
)) retval
= VBE_BROKEN_BIOS
;
666 #ifdef HAVE_VERBOSE_VAR
667 if(verbose
> 1) printf("vbelib: SetDisplayStart=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->SetDisplayStart
,pm_info
->SetDisplayStart
);
669 pm_info
->SetPaletteData
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->SetPaletteData
);
670 if(!is_addr_valid(pm_info
->SetPaletteData
)) retval
= VBE_BROKEN_BIOS
;
671 #ifdef HAVE_VERBOSE_VAR
672 if(verbose
> 1) printf("vbelib: SetPaletteData=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->SetPaletteData
,pm_info
->SetPaletteData
);
674 pm_info
->iopl_ports
= PhysToVirtSO(r
.es
,info_offset
+rm_info
->iopl_ports
);
675 if(!rm_info
->iopl_ports
) pm_info
->iopl_ports
= NULL
;
677 if(!check_wrd(pm_info
->iopl_ports
))
679 pm_info
->iopl_ports
= NULL
;
680 /* retval = VBE_BROKEN_BIOS; <- It's for broken BIOSes only */
682 #ifdef HAVE_VERBOSE_VAR
685 printf("vbelib: iopl_ports=%04X:%04X => %p\n",r
.es
,info_offset
+rm_info
->iopl_ports
,pm_info
->iopl_ports
);
686 if(pm_info
->iopl_ports
) print_wrd(pm_info
->iopl_ports
);
693 /* --------- Standard VGA stuff -------------- */
694 int vbeWriteString(int x
, int y
, int attr
, char *str
)
697 void *rm_space
= NULL
;
699 memset(&r
,0,sizeof(struct LRMI_regs
));
701 r
.edx
= ((y
<<8)&0xff00)|(x
&0xff);
703 if(!(rm_space
= LRMI_alloc_real(r
.ecx
))) return VBE_OUT_OF_DOS_MEM
;
704 r
.es
= VirtToPhysSeg(rm_space
);
705 r
.ebp
= VirtToPhysOff(rm_space
);
706 memcpy(rm_space
,str
,r
.ecx
);
708 retval
= VBE_LRMI_int(0x10,&r
);
709 LRMI_free_real(rm_space
);
710 if(!retval
) return VBE_VM86_FAIL
;
711 retval
= r
.eax
& 0xffff;
712 if(retval
== 0x4f) retval
= VBE_OK
;
716 void * vbeMapVideoBuffer(unsigned long phys_addr
,unsigned long size
)
719 if(fd_mem
== -1) return NULL
;
720 if(verbose
> 1) printf("vbelib: vbeMapVideoBuffer(%08lX,%08lX)\n",phys_addr
,size
);
721 /* Here we don't need with MAP_FIXED and prefered address (first argument) */
722 lfb
= mmap((void *)0,size
,PROT_READ
| PROT_WRITE
,MAP_SHARED
,fd_mem
,phys_addr
);
723 return lfb
== (void *)-1 ? 0 : lfb
;
726 void vbeUnmapVideoBuffer(unsigned long linear_addr
,unsigned long size
)
728 if(verbose
> 1) printf("vbelib: vbeUnmapVideoBuffer(%08lX,%08lX)\n",linear_addr
,size
);
729 munmap((void *)linear_addr
,size
);