Grabbing Monitor EDID Data on OpenSolaris
When working on the second release of BeleniX 2.5 years back which included Xorg 6.8 and Xfce for the first time, I needed a way grab the Monitor's EDID data. EDID stands for Extended Display Identification Data and is explained in this Wikipedia article. I modified the ddcxinfo utility used in Linux (KnoppiX) and used it for BeleniX. The ddcxinfo utility would process the EDID data and generate modeline and monitor refresh information while providing some useful options. Xorg auto-configuration would try to do that same but had vagaries. In general ddcxinfo seemed to produce better results using it's own logic.
That utility still persists today and had been giving good results till BeleniX 0.5.1. But in BeleniX 0.6 it has stopped working. Why ? Because of the integration of Direct Boot support in OpenSolaris! This needs some explanation.
In order to get the Monitor's EDID information one has to perform a DDC probe a technique defined by Video Electronics Standards Association or VESA for short. Typically on PCs there are BIOS extensions that support some of the VESA functionality including the ability to perform a DDC probe (Vesa Bios Extensions or VBE). So this is also called VBE probe. You typicall call int10h function 1 to fetch EDID data from the monitor. This is all fine but the problem is BIOS works in real mode while all modern Operating Systems including OpenSolaris run in protected mode. The BIOS is not active in protected mode. So to call a BIOS function you'd need to either use virtual 8086 mode or use an x86 real mode emulator. In Linux the kernel provides a vm86 system call that allows one to execute code in real mode that includes int10h BIOS calls. Vm86 uses the Virtual 8086 mode. There is a library called Linux Real Mode Interface that allows easily making real mode BIOS calls utilizing vm86.
Such a thing is not available on OpenSolaris however. But before Direct Boot was integrated OpenSolaris used the multiboot program to boot the kernel. Grub will load and pass information to the multiboot standalone program which will do some basic setup, load and jump into the the kernel. Multiboot ran in real mode and among other things used VBE to grab the monitor EDID information block. This can be seen in the vgaprobe.c file. Multiboot used to attach this raw EDID data as a property of the vgatext device node. Vgatext is the module on OpenSolaris that provides the text mode VGA console (80x25) on x86 platforms. This property was accessible via the Platform Information Control Library (See: man -s 3PICL libpicl). So my port of ddcxinfo utility simply queried PICL to extract the raw EDID information from the "display-edif-block" property. This would not work if Nvidia's binary driver was active since Nvidia Xorg binary driver uses the nvidia kernel module that replaces vgatext on machines with a supported Nvidia display card. This is a not a problem since the Nvidia driver does some custom probing and does a good job of selecting a usable display resolution and refresh.
Now the Direct Boot project got rid of multiboot for various reasons and along with it went the vga probing stuff. So vgatext no longer had the EDID information attached. I did not have time to look at this before BeleniX 0.6 release, so ddcxinfo fails to get EDID data and generates a set of standard predefined VESA modelines and some additional ones calculated using the VESA Generalized Timing Formula.
I started looking at this beginning of last week and noticed that Xorg itself would do a VBE Probe to get the EDID info. Sample /var/log/Xorg.<displaynum>.log extract:
(II) RADEON(0): initializing int10
(II) RADEON(0): Primary V_BIOS segment is: 0xc000
(II) RADEON(0): VESA BIOS detected
(II) RADEON(0): VbeVersion is 512, OemStringPtr is 0x00002100,
OemVendorNamePtr is 0x0000211c, OemProductNamePtr is 0x00002132,
OemProductRevPtr is 0x00002137
(II) RADEON(0): VESA VBE Version 2.0
(II) RADEON(0): VESA VBE Total Mem: 131072 kB
(II) RADEON(0): VESA VBE OEM: ATI MOBILITY RADEON 9600
(II) RADEON(0): VESA VBE OEM Software Rev: 1.0
(II) RADEON(0): VESA VBE OEM Vendor: ATI Technologies Inc.
(II) RADEON(0): VESA VBE OEM Product: P11
(II) RADEON(0): VESA VBE OEM Product Rev: 01.00
(II) Loading sub module "ddc"
(II) LoadModule: "ddc"
(II) Loading module ddc from path "/usr/X11/lib/modules/"
(II) Reloading /usr/X11/lib/modules//libddc.so
(II) RADEON(0): VESA VBE DDC supported
(II) RADEON(0): VESA VBE DDC Level 2
(II) RADEON(0): VESA VBE DDC transfer in appr. 2 sec.
(II) RADEON(0): VESA VBE DDC read successfully
...
...
(II) RADEON(0): DDC Type: 3, Detected Type: 0
(II) RADEON(0): EDID data from the display on port 1 ----------------------
(II) RADEON(0): Manufacturer: IDT Model: 2 Serial#: 0
(II) RADEON(0): Year: 1990 Week: 0
(II) RADEON(0): EDID Version: 1.3
Which means that it is able to make the int10h call even in OpenSolaris. A lot of digging later I found that Xorg used a real mode x86 emulator aptly called x86emu that was originally authored by Scitechsoft and their original now obsolete version is available here. The x86emu code in Xorg is at hw/xfree86/x86emu. Xorg has another module called vbe that calls into the int10 module for VBE BIOS calls. The int10 module uses x86emu which has the ability to execute the Vesa Bios Extensions. The DDC (Display Data Channel) protocol support is in hw/xfree86/ddc.
As far as I looked almost all of the Xorg Video drivers do have code to probe the Monitor and extract EDID data. Even the Nvidia binary driver does this, but probably in it's own way. In fact the big advantage is that the drivers can and do print this EDID data by calling some generic functions. See: print_edid.c.
The drivers will dump the raw EDID data block to Xorg.<displaynum>.log if verbose logging is enabled, in other word we execute: Xorg -logverbose 10. However that command starts the Xserver and it dosen't exit by itself. We need to run the Xserver, have it probe and log everything and come out, so that our little ddcxinfo utility can process that data. That is fortunately possible using: Xorg -logverbose 10 -probeonly. Sample output showing an EDID dump for the LCD monitor on my Ferrari 3400:
(II) RADEON(0): EDID (in hex):
(II) RADEON(0): 00ffffffffffff002494020000000000
(II) RADEON(0): 00000103801e17780acd7591554f8b26
(II) RADEON(0): 21505400000001010101010101010101
(II) RADEON(0): 010101010101302a78f0501a0f403070
(II) RADEON(0): 130031e41000001e0000000f0008fa22
(II) RADEON(0): ff023e07bbffffffff00000000fe0049
(II) RADEON(0): 44540a202020202020202020000000fe
(II) RADEON(0): 004e31353050320a202020202020003c
(II) RADEON(0):
Thus I modified the ddcxinfo utility to parse the verbose Xorg logfile and extract out the raw EDID data and interpret it. This is working as of now and will make it's way into BeleniX 0.6.1. The Nvidia binary driver also logs raw EDID data but in a slightly different format. ddcxinfo-belenix can handle that as well.
Having done all this I feel a desire to see the day when this extra processing will become obsolete. Simply running Xorg will give an optimum display out of the box. It is good to note that development efforts in Xorg is moving in that direction. For eg. a lot of effort has been put into the Xorg radeon driver to improve auto-configuration. In fact the ddcxinfo utility in BeleniX 0.6.1 will not apply it's own logic if it detects a supported Nvidia or ATI card, leaving the auto-configuration upto the driver.
Posted by satish s nandihalli on June 14, 2007 at 02:30 AM PDT #