135c4bbdfSmrg/* xf86DDC.c
235c4bbdfSmrg *
36747b715Smrg * Copyright 1998,1999 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
46747b715Smrg */
56747b715Smrg
66747b715Smrg/*
76747b715Smrg * A note on terminology.  DDC1 is the original dumb serial protocol, and
86747b715Smrg * can only do up to 128 bytes of EDID.  DDC2 is I2C-encapsulated and
96747b715Smrg * introduces extension blocks.  EDID is the old display identification
106747b715Smrg * block, DisplayID is the new one.
116747b715Smrg */
126747b715Smrg
136747b715Smrg#ifdef HAVE_XORG_CONFIG_H
146747b715Smrg#include <xorg-config.h>
156747b715Smrg#endif
166747b715Smrg
176747b715Smrg#include "misc.h"
186747b715Smrg#include "xf86.h"
196747b715Smrg#include "xf86_OSproc.h"
206747b715Smrg#include "xf86DDC.h"
216747b715Smrg#include <string.h>
226747b715Smrg
236747b715Smrg#define RETRIES 4
246747b715Smrg
256747b715Smrgtypedef enum {
266747b715Smrg    DDCOPT_NODDC1,
276747b715Smrg    DDCOPT_NODDC2,
286747b715Smrg    DDCOPT_NODDC
296747b715Smrg} DDCOpts;
306747b715Smrg
316747b715Smrgstatic const OptionInfoRec DDCOptions[] = {
3235c4bbdfSmrg    {DDCOPT_NODDC1, "NoDDC1", OPTV_BOOLEAN, {0}, FALSE},
3335c4bbdfSmrg    {DDCOPT_NODDC2, "NoDDC2", OPTV_BOOLEAN, {0}, FALSE},
3435c4bbdfSmrg    {DDCOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE},
3535c4bbdfSmrg    {-1, NULL, OPTV_NONE, {0}, FALSE},
366747b715Smrg};
376747b715Smrg
386747b715Smrg/* DDC1 */
396747b715Smrg
406747b715Smrgstatic int
416747b715Smrgfind_start(unsigned int *ptr)
426747b715Smrg{
436747b715Smrg    unsigned int comp[9], test[9];
4435c4bbdfSmrg    int i, j;
4535c4bbdfSmrg
4635c4bbdfSmrg    for (i = 0; i < 9; i++) {
4735c4bbdfSmrg        comp[i] = *(ptr++);
4835c4bbdfSmrg        test[i] = 1;
496747b715Smrg    }
5035c4bbdfSmrg    for (i = 0; i < 127; i++) {
5135c4bbdfSmrg        for (j = 0; j < 9; j++) {
5235c4bbdfSmrg            test[j] = test[j] & !(comp[j] ^ *(ptr++));
5335c4bbdfSmrg        }
546747b715Smrg    }
5535c4bbdfSmrg    for (i = 0; i < 9; i++)
5635c4bbdfSmrg        if (test[i])
5735c4bbdfSmrg            return i + 1;
586747b715Smrg    return -1;
596747b715Smrg}
606747b715Smrg
616747b715Smrgstatic unsigned char *
626747b715Smrgfind_header(unsigned char *block)
636747b715Smrg{
646747b715Smrg    unsigned char *ptr, *head_ptr, *end;
6535c4bbdfSmrg    unsigned char header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
6635c4bbdfSmrg
676747b715Smrg    ptr = block;
686747b715Smrg    end = block + EDID1_LEN;
6935c4bbdfSmrg    while (ptr < end) {
7035c4bbdfSmrg        int i;
7135c4bbdfSmrg
7235c4bbdfSmrg        head_ptr = ptr;
7335c4bbdfSmrg        for (i = 0; i < 8; i++) {
7435c4bbdfSmrg            if (header[i] != *(head_ptr++))
7535c4bbdfSmrg                break;
7635c4bbdfSmrg            if (head_ptr == end)
7735c4bbdfSmrg                head_ptr = block;
7835c4bbdfSmrg        }
7935c4bbdfSmrg        if (i == 8)
8035c4bbdfSmrg            break;
8135c4bbdfSmrg        ptr++;
826747b715Smrg    }
8335c4bbdfSmrg    if (ptr == end)
8435c4bbdfSmrg        return NULL;
856747b715Smrg    return ptr;
866747b715Smrg}
876747b715Smrg
886747b715Smrgstatic unsigned char *
896747b715Smrgresort(unsigned char *s_block)
906747b715Smrg{
916747b715Smrg    unsigned char *d_new, *d_ptr, *d_end, *s_ptr, *s_end;
926747b715Smrg    unsigned char tmp;
936747b715Smrg
9435c4bbdfSmrg    s_ptr = find_header(s_block);
9535c4bbdfSmrg    if (!s_ptr)
9635c4bbdfSmrg        return NULL;
976747b715Smrg    s_end = s_block + EDID1_LEN;
9835c4bbdfSmrg
996747b715Smrg    d_new = malloc(EDID1_LEN);
10035c4bbdfSmrg    if (!d_new)
10135c4bbdfSmrg        return NULL;
1026747b715Smrg    d_end = d_new + EDID1_LEN;
1036747b715Smrg
10435c4bbdfSmrg    for (d_ptr = d_new; d_ptr < d_end; d_ptr++) {
10535c4bbdfSmrg        tmp = *(s_ptr++);
10635c4bbdfSmrg        *d_ptr = tmp;
10735c4bbdfSmrg        if (s_ptr == s_end)
10835c4bbdfSmrg            s_ptr = s_block;
1096747b715Smrg    }
1106747b715Smrg    free(s_block);
1116747b715Smrg    return d_new;
1126747b715Smrg}
1136747b715Smrg
1146747b715Smrgstatic int
1156747b715SmrgDDC_checksum(const unsigned char *block, int len)
1166747b715Smrg{
1176747b715Smrg    int i, result = 0;
1186747b715Smrg    int not_null = 0;
11935c4bbdfSmrg
12035c4bbdfSmrg    for (i = 0; i < len; i++) {
12135c4bbdfSmrg        not_null |= block[i];
12235c4bbdfSmrg        result += block[i];
1236747b715Smrg    }
12435c4bbdfSmrg
1256747b715Smrg#ifdef DEBUG
12635c4bbdfSmrg    if (result & 0xFF)
12735c4bbdfSmrg        ErrorF("DDC checksum not correct\n");
12835c4bbdfSmrg    if (!not_null)
12935c4bbdfSmrg        ErrorF("DDC read all Null\n");
1306747b715Smrg#endif
1316747b715Smrg
1326747b715Smrg    /* catch the trivial case where all bytes are 0 */
13335c4bbdfSmrg    if (!not_null)
13435c4bbdfSmrg        return 1;
1356747b715Smrg
13635c4bbdfSmrg    return result & 0xFF;
1376747b715Smrg}
1386747b715Smrg
1396747b715Smrgstatic unsigned char *
1406747b715SmrgGetEDID_DDC1(unsigned int *s_ptr)
1416747b715Smrg{
1426747b715Smrg    unsigned char *d_block, *d_pos;
1436747b715Smrg    unsigned int *s_pos, *s_end;
1446747b715Smrg    int s_start;
14535c4bbdfSmrg    int i, j;
14635c4bbdfSmrg
1476747b715Smrg    s_start = find_start(s_ptr);
14835c4bbdfSmrg    if (s_start == -1)
14935c4bbdfSmrg        return NULL;
1506747b715Smrg    s_end = s_ptr + NUM;
1516747b715Smrg    s_pos = s_ptr + s_start;
1521b5d61b8Smrg    d_block = calloc(1, EDID1_LEN);
15335c4bbdfSmrg    if (!d_block)
15435c4bbdfSmrg        return NULL;
1556747b715Smrg    d_pos = d_block;
15635c4bbdfSmrg    for (i = 0; i < EDID1_LEN; i++) {
15735c4bbdfSmrg        for (j = 0; j < 8; j++) {
15835c4bbdfSmrg            *d_pos <<= 1;
15935c4bbdfSmrg            if (*s_pos) {
16035c4bbdfSmrg                *d_pos |= 0x01;
16135c4bbdfSmrg            }
16235c4bbdfSmrg            s_pos++;
16335c4bbdfSmrg            if (s_pos == s_end)
16435c4bbdfSmrg                s_pos = s_ptr;
16535c4bbdfSmrg        };
16635c4bbdfSmrg        s_pos++;
16735c4bbdfSmrg        if (s_pos == s_end)
16835c4bbdfSmrg            s_pos = s_ptr;
16935c4bbdfSmrg        d_pos++;
1706747b715Smrg    }
1716747b715Smrg    free(s_ptr);
17235c4bbdfSmrg    if (d_block && DDC_checksum(d_block, EDID1_LEN)) {
17335c4bbdfSmrg        free(d_block);
17435c4bbdfSmrg        return NULL;
1756747b715Smrg    }
1766747b715Smrg    return (resort(d_block));
1776747b715Smrg}
1786747b715Smrg
1796747b715Smrg/* fetch entire EDID record; DDC bit needs to be masked */
18035c4bbdfSmrgstatic unsigned int *
1816747b715SmrgFetchEDID_DDC1(register ScrnInfoPtr pScrn,
18235c4bbdfSmrg               register unsigned int (*read_DDC) (ScrnInfoPtr))
1836747b715Smrg{
1846747b715Smrg    int count = NUM;
1856747b715Smrg    unsigned int *ptr, *xp;
1866747b715Smrg
18735c4bbdfSmrg    ptr = xp = malloc(sizeof(int) * NUM);
1886747b715Smrg
18935c4bbdfSmrg    if (!ptr)
19035c4bbdfSmrg        return NULL;
1916747b715Smrg    do {
19235c4bbdfSmrg        /* wait for next retrace */
19335c4bbdfSmrg        *xp = read_DDC(pScrn);
19435c4bbdfSmrg        xp++;
19535c4bbdfSmrg    } while (--count);
1966747b715Smrg    return ptr;
1976747b715Smrg}
1986747b715Smrg
1996747b715Smrg/* test if DDC1  return 0 if not */
2006747b715Smrgstatic Bool
20135c4bbdfSmrgTestDDC1(ScrnInfoPtr pScrn, unsigned int (*read_DDC) (ScrnInfoPtr))
2026747b715Smrg{
2036747b715Smrg    int old, count;
2046747b715Smrg
2056747b715Smrg    old = read_DDC(pScrn);
2066747b715Smrg    count = HEADER * BITS_PER_BYTE;
2076747b715Smrg    do {
20835c4bbdfSmrg        /* wait for next retrace */
20935c4bbdfSmrg        if (old != read_DDC(pScrn))
21035c4bbdfSmrg            break;
21135c4bbdfSmrg    } while (count--);
2126747b715Smrg    return count;
2136747b715Smrg}
2146747b715Smrg
21535c4bbdfSmrg/*
2166747b715Smrg * read EDID record , pass it to callback function to interpret.
2176747b715Smrg * callback function will store it for further use by calling
21835c4bbdfSmrg * function; it will also decide if we need to reread it
2196747b715Smrg */
2206747b715Smrgstatic unsigned char *
22135c4bbdfSmrgEDIDRead_DDC1(ScrnInfoPtr pScrn, DDC1SetSpeedProc DDCSpeed,
22235c4bbdfSmrg              unsigned int (*read_DDC) (ScrnInfoPtr))
2236747b715Smrg{
2246747b715Smrg    unsigned char *EDID_block = NULL;
2256747b715Smrg    int count = RETRIES;
2266747b715Smrg
22735c4bbdfSmrg    if (!read_DDC) {
22835c4bbdfSmrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
22935c4bbdfSmrg                   "chipset doesn't support DDC1\n");
23035c4bbdfSmrg        return NULL;
2316747b715Smrg    };
2326747b715Smrg
23335c4bbdfSmrg    if (TestDDC1(pScrn, read_DDC) == -1) {
23435c4bbdfSmrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No DDC signal\n");
23535c4bbdfSmrg        return NULL;
2366747b715Smrg    };
2376747b715Smrg
23835c4bbdfSmrg    if (DDCSpeed)
23935c4bbdfSmrg        DDCSpeed(pScrn, DDC_FAST);
2406747b715Smrg    do {
24135c4bbdfSmrg        EDID_block = GetEDID_DDC1(FetchEDID_DDC1(pScrn, read_DDC));
24235c4bbdfSmrg        count--;
2436747b715Smrg    } while (!EDID_block && count);
24435c4bbdfSmrg    if (DDCSpeed)
24535c4bbdfSmrg        DDCSpeed(pScrn, DDC_SLOW);
2466747b715Smrg
2476747b715Smrg    return EDID_block;
2486747b715Smrg}
2496747b715Smrg
2506747b715Smrg/**
2516747b715Smrg * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC1 are
2526747b715Smrg * unset.  EDID information blocks are interpreted and the results returned in
2536747b715Smrg * an xf86MonPtr.
2546747b715Smrg *
2556747b715Smrg * This function does not affect the list of modes used by drivers -- it is up
2566747b715Smrg * to the driver to decide policy on what to do with EDID information.
2576747b715Smrg *
2586747b715Smrg * @return pointer to a new xf86MonPtr containing the EDID information.
2596747b715Smrg * @return NULL if no monitor attached or failure to interpret the EDID.
2606747b715Smrg */
2616747b715Smrgxf86MonPtr
26235c4bbdfSmrgxf86DoEDID_DDC1(ScrnInfoPtr pScrn, DDC1SetSpeedProc DDC1SetSpeed,
26335c4bbdfSmrg                unsigned int (*DDC1Read) (ScrnInfoPtr))
2646747b715Smrg{
2656747b715Smrg    unsigned char *EDID_block = NULL;
2666747b715Smrg    xf86MonPtr tmp = NULL;
26735c4bbdfSmrg
2686747b715Smrg    /* Default DDC and DDC1 to enabled. */
2696747b715Smrg    Bool noddc = FALSE, noddc1 = FALSE;
2706747b715Smrg    OptionInfoPtr options;
2716747b715Smrg
2726747b715Smrg    options = xnfalloc(sizeof(DDCOptions));
27335c4bbdfSmrg    (void) memcpy(options, DDCOptions, sizeof(DDCOptions));
2746747b715Smrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
2756747b715Smrg
2766747b715Smrg    xf86GetOptValBool(options, DDCOPT_NODDC, &noddc);
2776747b715Smrg    xf86GetOptValBool(options, DDCOPT_NODDC1, &noddc1);
2786747b715Smrg    free(options);
27935c4bbdfSmrg
2806747b715Smrg    if (noddc || noddc1)
28135c4bbdfSmrg        return NULL;
28235c4bbdfSmrg
2839ace9065Smrg    OsBlockSignals();
28435c4bbdfSmrg    EDID_block = EDIDRead_DDC1(pScrn, DDC1SetSpeed, DDC1Read);
2859ace9065Smrg    OsReleaseSignals();
2866747b715Smrg
28735c4bbdfSmrg    if (EDID_block) {
28835c4bbdfSmrg        tmp = xf86InterpretEDID(pScrn->scrnIndex, EDID_block);
2896747b715Smrg    }
2906747b715Smrg#ifdef DEBUG
29135c4bbdfSmrg    else
29235c4bbdfSmrg        ErrorF("No EDID block returned\n");
2936747b715Smrg    if (!tmp)
29435c4bbdfSmrg        ErrorF("Cannot interpret EDID block\n");
2956747b715Smrg#endif
29635c4bbdfSmrg    return tmp;
2976747b715Smrg}
2986747b715Smrg
2996747b715Smrg/* DDC2 */
3006747b715Smrg
3016747b715Smrgstatic I2CDevPtr
30235c4bbdfSmrgDDC2MakeDevice(I2CBusPtr pBus, int address, const char *name)
3036747b715Smrg{
3046747b715Smrg    I2CDevPtr dev = NULL;
3056747b715Smrg
3066747b715Smrg    if (!(dev = xf86I2CFindDev(pBus, address))) {
30735c4bbdfSmrg        dev = xf86CreateI2CDevRec();
30835c4bbdfSmrg        dev->DevName = name;
30935c4bbdfSmrg        dev->SlaveAddr = address;
31035c4bbdfSmrg        dev->ByteTimeout = 2200;        /* VESA DDC spec 3 p. 43 (+10 %) */
31135c4bbdfSmrg        dev->StartTimeout = 550;
31235c4bbdfSmrg        dev->BitTimeout = 40;
31335c4bbdfSmrg        dev->AcknTimeout = 40;
31435c4bbdfSmrg
31535c4bbdfSmrg        dev->pI2CBus = pBus;
31635c4bbdfSmrg        if (!xf86I2CDevInit(dev)) {
31735c4bbdfSmrg            xf86DrvMsg(pBus->scrnIndex, X_PROBED, "No DDC2 device\n");
31835c4bbdfSmrg            return NULL;
31935c4bbdfSmrg        }
3206747b715Smrg    }
3216747b715Smrg
3226747b715Smrg    return dev;
3236747b715Smrg}
3246747b715Smrg
3256747b715Smrgstatic I2CDevPtr
32635c4bbdfSmrgDDC2Init(I2CBusPtr pBus)
3276747b715Smrg{
3286747b715Smrg    I2CDevPtr dev = NULL;
3296747b715Smrg
3306747b715Smrg    /*
33135c4bbdfSmrg     * Slow down the bus so that older monitors don't
3326747b715Smrg     * miss things.
3336747b715Smrg     */
3346747b715Smrg    pBus->RiseFallTime = 20;
33535c4bbdfSmrg
3366747b715Smrg    dev = DDC2MakeDevice(pBus, 0x00A0, "ddc2");
3376747b715Smrg    if (xf86I2CProbeAddress(pBus, 0x0060))
33835c4bbdfSmrg        DDC2MakeDevice(pBus, 0x0060, "E-EDID segment register");
3396747b715Smrg
3406747b715Smrg    return dev;
3416747b715Smrg}
3426747b715Smrg
3436747b715Smrg/* Mmmm, smell the hacks */
3446747b715Smrgstatic void
3456747b715SmrgEEDIDStop(I2CDevPtr d)
3466747b715Smrg{
3476747b715Smrg}
3486747b715Smrg
3496747b715Smrg/* block is the EDID block number.  a segment is two blocks. */
3506747b715Smrgstatic Bool
3516747b715SmrgDDC2Read(I2CDevPtr dev, int block, unsigned char *R_Buffer)
3526747b715Smrg{
3536747b715Smrg    unsigned char W_Buffer[1];
3546747b715Smrg    int i, segment;
3556747b715Smrg    I2CDevPtr seg;
35635c4bbdfSmrg    void (*stop) (I2CDevPtr);
3576747b715Smrg
3586747b715Smrg    for (i = 0; i < RETRIES; i++) {
35935c4bbdfSmrg        /* Stop bits reset the segment pointer to 0, so be careful here. */
36035c4bbdfSmrg        segment = block >> 1;
36135c4bbdfSmrg        if (segment) {
36235c4bbdfSmrg            Bool b;
36335c4bbdfSmrg
36435c4bbdfSmrg            if (!(seg = xf86I2CFindDev(dev->pI2CBus, 0x0060)))
36535c4bbdfSmrg                return FALSE;
36635c4bbdfSmrg
36735c4bbdfSmrg            W_Buffer[0] = segment;
36835c4bbdfSmrg
36935c4bbdfSmrg            stop = dev->pI2CBus->I2CStop;
37035c4bbdfSmrg            dev->pI2CBus->I2CStop = EEDIDStop;
37135c4bbdfSmrg
37235c4bbdfSmrg            b = xf86I2CWriteRead(seg, W_Buffer, 1, NULL, 0);
37335c4bbdfSmrg
37435c4bbdfSmrg            dev->pI2CBus->I2CStop = stop;
37535c4bbdfSmrg            if (!b) {
37635c4bbdfSmrg                dev->pI2CBus->I2CStop(dev);
37735c4bbdfSmrg                continue;
37835c4bbdfSmrg            }
37935c4bbdfSmrg        }
38035c4bbdfSmrg
38135c4bbdfSmrg        W_Buffer[0] = (block & 0x01) * EDID1_LEN;
38235c4bbdfSmrg
38335c4bbdfSmrg        if (xf86I2CWriteRead(dev, W_Buffer, 1, R_Buffer, EDID1_LEN)) {
38435c4bbdfSmrg            if (!DDC_checksum(R_Buffer, EDID1_LEN))
38535c4bbdfSmrg                return TRUE;
38635c4bbdfSmrg        }
3876747b715Smrg    }
38835c4bbdfSmrg
3896747b715Smrg    return FALSE;
3906747b715Smrg}
3916747b715Smrg
3926747b715Smrg/**
3936747b715Smrg * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are
3946747b715Smrg * unset.  EDID information blocks are interpreted and the results returned in
3956747b715Smrg * an xf86MonPtr.  Unlike xf86DoEDID_DDC[12](), this function will return
3966747b715Smrg * the complete EDID data, including all extension blocks, if the 'complete'
3976747b715Smrg * parameter is TRUE;
3986747b715Smrg *
3996747b715Smrg * This function does not affect the list of modes used by drivers -- it is up
4006747b715Smrg * to the driver to decide policy on what to do with EDID information.
4016747b715Smrg *
4026747b715Smrg * @return pointer to a new xf86MonPtr containing the EDID information.
4036747b715Smrg * @return NULL if no monitor attached or failure to interpret the EDID.
4046747b715Smrg */
4056747b715Smrgxf86MonPtr
40635c4bbdfSmrgxf86DoEEDID(ScrnInfoPtr pScrn, I2CBusPtr pBus, Bool complete)
4076747b715Smrg{
4086747b715Smrg    unsigned char *EDID_block = NULL;
4096747b715Smrg    xf86MonPtr tmp = NULL;
4106747b715Smrg    I2CDevPtr dev = NULL;
41135c4bbdfSmrg
4126747b715Smrg    /* Default DDC and DDC2 to enabled. */
4136747b715Smrg    Bool noddc = FALSE, noddc2 = FALSE;
4146747b715Smrg    OptionInfoPtr options;
4156747b715Smrg
4166747b715Smrg    options = malloc(sizeof(DDCOptions));
4176747b715Smrg    if (!options)
41835c4bbdfSmrg        return NULL;
4196747b715Smrg    memcpy(options, DDCOptions, sizeof(DDCOptions));
4206747b715Smrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
4216747b715Smrg
4226747b715Smrg    xf86GetOptValBool(options, DDCOPT_NODDC, &noddc);
4236747b715Smrg    xf86GetOptValBool(options, DDCOPT_NODDC2, &noddc2);
4246747b715Smrg    free(options);
4256747b715Smrg
4266747b715Smrg    if (noddc || noddc2)
42735c4bbdfSmrg        return NULL;
4286747b715Smrg
42935c4bbdfSmrg    if (!(dev = DDC2Init(pBus)))
43035c4bbdfSmrg        return NULL;
4316747b715Smrg
4326747b715Smrg    EDID_block = calloc(1, EDID1_LEN);
4336747b715Smrg    if (!EDID_block)
43435c4bbdfSmrg        return NULL;
4356747b715Smrg
4366747b715Smrg    if (DDC2Read(dev, 0, EDID_block)) {
43735c4bbdfSmrg        int i, n = EDID_block[0x7e];
4386747b715Smrg
43935c4bbdfSmrg        if (complete && n) {
44035c4bbdfSmrg            EDID_block = reallocarray(EDID_block, 1 + n, EDID1_LEN);
4416747b715Smrg
44235c4bbdfSmrg            for (i = 0; i < n; i++)
44335c4bbdfSmrg                DDC2Read(dev, i + 1, EDID_block + (EDID1_LEN * (1 + i)));
44435c4bbdfSmrg        }
4456747b715Smrg
44635c4bbdfSmrg        tmp = xf86InterpretEEDID(pScrn->scrnIndex, EDID_block);
4476747b715Smrg    }
4486747b715Smrg
4496747b715Smrg    if (tmp && complete)
45035c4bbdfSmrg        tmp->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
4516747b715Smrg
4526747b715Smrg    return tmp;
4536747b715Smrg}
4546747b715Smrg
4556747b715Smrg/**
4566747b715Smrg * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are
4576747b715Smrg * unset.  EDID information blocks are interpreted and the results returned in
4586747b715Smrg * an xf86MonPtr.
4596747b715Smrg *
4606747b715Smrg * This function does not affect the list of modes used by drivers -- it is up
4616747b715Smrg * to the driver to decide policy on what to do with EDID information.
4626747b715Smrg *
4636747b715Smrg * @return pointer to a new xf86MonPtr containing the EDID information.
4646747b715Smrg * @return NULL if no monitor attached or failure to interpret the EDID.
4656747b715Smrg */
4666747b715Smrgxf86MonPtr
46735c4bbdfSmrgxf86DoEDID_DDC2(ScrnInfoPtr pScrn, I2CBusPtr pBus)
4686747b715Smrg{
46935c4bbdfSmrg    return xf86DoEEDID(pScrn, pBus, FALSE);
4706747b715Smrg}
471