, 2 min read

Patching Faulty EDID Information

Some computer monitors either do not provide correct EDID, or no EDID at all. An example monitor is LG E2340T. In this case you can provide a hand-crafted EDID file in xorg.conf. For setting the correct screen resolution in the EDID file you can either use a hex-editor, or use below short C program.

The C program reads a "half-way" working EDID file and changes resolution to the required values. It does this by modifying the bytes at positions (56, 58, 59, 61) and (74, 76, 77, 79).

// This program was written by Gordian Edenhofer on 04-May-2014
// It is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
// Simple EDID Manipulation Tool
// Usage: semt [Inputfile] [X-Resolution] [Y-Resolution] [Outputfile] [Options]

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main (int argc, char *argv[]) {
        int i, c, x_res, y_res, checksum = 0, debug=0;
        unsigned char edid[128];
        FILE *fp;

        while ((c = getopt(argc,argv,"dvh")) != -1) {
                // ...
        }

        if (argc-optind != 4) {
                printf("%s: is meant to be used with the following arguments [Inputfile] [X-Resolution] [Y-Resolution] [Outputfile]\n",argv[0]);
                return 1;
        }

        if ((fp = fopen(argv[optind],"r")) == NULL) { ... }
        if (fread( edid, 1, 128, fp ) != 128) { ... }
        if (fclose(fp) != 0) { ... }

        x_res = atoi(argv[optind+1]);
        y_res = atoi(argv[optind+2]);

        // Dumping X-Resolution to EDID
        edid[56] = x_res%256;
        edid[58] = (x_res/256)*16;
        edid[74] = x_res%256;
        edid[76] = (x_res/256)*16;

        // Dumping Y-Resolution to EDID
        edid[59] = y_res%256;
        edid[61] = (y_res/256)*16;
        edid[77] = y_res%256;
        edid[79] = (y_res/256)*16;
        y_res = atoi(argv[optind+2]);

        // Dumping X-Resolution to EDID
        edid[56] = x_res%256;
        edid[58] = (x_res/256)*16;
        edid[74] = x_res%256;
        edid[76] = (x_res/256)*16;

        // Dumping Y-Resolution to EDID
        edid[59] = y_res%256;
        edid[61] = (y_res/256)*16;
        edid[77] = y_res%256;
        edid[79] = (y_res/256)*16;

        // Calculating and writing the checksum
        for (i=0; i<=126; ++i)
                checksum += edid[i];
        checksum %= 256;
        edid[127] = (256-checksum)%256;

        if ((fp = fopen(argv[optind+3],"w")) == NULL) { ... }
        if (fwrite(edid,1,128,fp) != 128) { ... }
        if (fclose(fp) != 0) { ... }

        return 0;
}

The complete source code for semt.c is in GitHub. An example EDID file is in edid.bin.

The difficulty was to come up with the correct bytes to change. The program parse-edid in read-edid was a very helpful guide here. parse-edid is contained in Debian package read-edid.

Using the modified EDID in xorg.conf goes like this:

Section "Screen"
        Identifier     "Screen0"
        Device         "Device0"
        Monitor        "Monitor0"
        DefaultDepth    24
        Option         "CustomEDID" "CRT-1:/etc/X11/LG2.bin"
#       Option         "UseEdid" "False"
        Option         "TwinView" "0"
        Option         "metamodes" "1920x1080 +0+0"

        SubSection     "Display"
                Depth       24
        EndSubSection
EndSection


Section "Device"
        Identifier      "Device0"
#       Option  "NoLogo"        "True"
EndSection

Use either CRT-0 or CRT-1 depending on which connector of the graphic card the monitor is plugged on.

More on EDID and fixing stuff in xorg.conf: Workaround buggy HDMI audio with EDID modification. EDID standard is here: EDID standard.

Added 12-Jul-2015: There is an AUR package for semt: aur.archlinux.org/packages/semt/.