xref: /reactos/win32ss/drivers/videoprt/ddc.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * VideoPort driver
3*c2c66affSColin Finck  *
4*c2c66affSColin Finck  * Copyright (C) 2002, 2003, 2004 ReactOS Team
5*c2c66affSColin Finck  *
6*c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7*c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8*c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9*c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10*c2c66affSColin Finck  *
11*c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12*c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*c2c66affSColin Finck  * Lesser General Public License for more details.
15*c2c66affSColin Finck  *
16*c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17*c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18*c2c66affSColin Finck  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19*c2c66affSColin Finck  *
20*c2c66affSColin Finck  */
21*c2c66affSColin Finck 
22*c2c66affSColin Finck #include "videoprt.h"
23*c2c66affSColin Finck 
24*c2c66affSColin Finck #define NDEBUG
25*c2c66affSColin Finck #include <debug.h>
26*c2c66affSColin Finck 
27*c2c66affSColin Finck #define DDC_EEPROM_ADDRESS  0xA0
28*c2c66affSColin Finck 
29*c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/
30*c2c66affSColin Finck 
31*c2c66affSColin Finck #define LOW               0
32*c2c66affSColin Finck #define HIGH              1
33*c2c66affSColin Finck #define WRITE             0
34*c2c66affSColin Finck #define READ              1
35*c2c66affSColin Finck #define READ_SDA()        (i2c->ReadDataLine(HwDeviceExtension))
36*c2c66affSColin Finck #define READ_SCL()        (i2c->ReadClockLine(HwDeviceExtension))
37*c2c66affSColin Finck #define WRITE_SDA(state)  (i2c->WriteDataLine(HwDeviceExtension, state))
38*c2c66affSColin Finck #define WRITE_SCL(state)  (i2c->WriteClockLine(HwDeviceExtension, state))
39*c2c66affSColin Finck 
40*c2c66affSColin Finck static LARGE_INTEGER HalfPeriodDelay = {{0, 70}};
41*c2c66affSColin Finck #define DELAY_HALF()      KeDelayExecutionThread(KernelMode, FALSE, &HalfPeriodDelay)
42*c2c66affSColin Finck 
43*c2c66affSColin Finck 
44*c2c66affSColin Finck static BOOL
I2CWrite(PVOID HwDeviceExtension,PI2C_CALLBACKS i2c,UCHAR Data)45*c2c66affSColin Finck I2CWrite(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Data)
46*c2c66affSColin Finck {
47*c2c66affSColin Finck    UCHAR Bit;
48*c2c66affSColin Finck    BOOL Ack;
49*c2c66affSColin Finck 
50*c2c66affSColin Finck    /* transmit data */
51*c2c66affSColin Finck    for (Bit = (1 << 7); Bit != 0; Bit >>= 1)
52*c2c66affSColin Finck      {
53*c2c66affSColin Finck         WRITE_SCL(LOW);
54*c2c66affSColin Finck         WRITE_SDA((Data & Bit) ? HIGH : LOW);
55*c2c66affSColin Finck         DELAY_HALF();
56*c2c66affSColin Finck         WRITE_SCL(HIGH);
57*c2c66affSColin Finck         DELAY_HALF();
58*c2c66affSColin Finck      }
59*c2c66affSColin Finck 
60*c2c66affSColin Finck    /* get ack */
61*c2c66affSColin Finck    WRITE_SCL(LOW);
62*c2c66affSColin Finck    WRITE_SDA(HIGH);
63*c2c66affSColin Finck    DELAY_HALF();
64*c2c66affSColin Finck    WRITE_SCL(HIGH);
65*c2c66affSColin Finck    do
66*c2c66affSColin Finck      {
67*c2c66affSColin Finck         DELAY_HALF();
68*c2c66affSColin Finck      }
69*c2c66affSColin Finck    while (READ_SCL() != HIGH);
70*c2c66affSColin Finck    Ack = (READ_SDA() == LOW);
71*c2c66affSColin Finck    DELAY_HALF();
72*c2c66affSColin Finck 
73*c2c66affSColin Finck    INFO_(VIDEOPRT, "I2CWrite: %s\n", Ack ? "Ack" : "Nak");
74*c2c66affSColin Finck    return Ack;
75*c2c66affSColin Finck }
76*c2c66affSColin Finck 
77*c2c66affSColin Finck 
78*c2c66affSColin Finck static UCHAR
I2CRead(PVOID HwDeviceExtension,PI2C_CALLBACKS i2c,BOOL Ack)79*c2c66affSColin Finck I2CRead(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, BOOL Ack)
80*c2c66affSColin Finck {
81*c2c66affSColin Finck    INT Bit = 0x80;
82*c2c66affSColin Finck    UCHAR Data = 0;
83*c2c66affSColin Finck 
84*c2c66affSColin Finck    /* pull down SCL and release SDA */
85*c2c66affSColin Finck    WRITE_SCL(LOW);
86*c2c66affSColin Finck    WRITE_SDA(HIGH);
87*c2c66affSColin Finck 
88*c2c66affSColin Finck    /* read byte */
89*c2c66affSColin Finck    for (Bit = (1 << 7); Bit != 0; Bit >>= 1)
90*c2c66affSColin Finck      {
91*c2c66affSColin Finck         WRITE_SCL(LOW);
92*c2c66affSColin Finck         DELAY_HALF();
93*c2c66affSColin Finck         WRITE_SCL(HIGH);
94*c2c66affSColin Finck         DELAY_HALF();
95*c2c66affSColin Finck         if (READ_SDA() == HIGH)
96*c2c66affSColin Finck           Data |= Bit;
97*c2c66affSColin Finck      }
98*c2c66affSColin Finck 
99*c2c66affSColin Finck    /* send ack/nak */
100*c2c66affSColin Finck    WRITE_SCL(LOW);
101*c2c66affSColin Finck    WRITE_SDA(Ack ? LOW : HIGH);
102*c2c66affSColin Finck    DELAY_HALF();
103*c2c66affSColin Finck    WRITE_SCL(HIGH);
104*c2c66affSColin Finck    do
105*c2c66affSColin Finck      {
106*c2c66affSColin Finck         DELAY_HALF();
107*c2c66affSColin Finck      }
108*c2c66affSColin Finck    while (READ_SCL() != HIGH);
109*c2c66affSColin Finck 
110*c2c66affSColin Finck    return Data;
111*c2c66affSColin Finck }
112*c2c66affSColin Finck 
113*c2c66affSColin Finck 
114*c2c66affSColin Finck static VOID
I2CStop(PVOID HwDeviceExtension,PI2C_CALLBACKS i2c)115*c2c66affSColin Finck I2CStop(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c)
116*c2c66affSColin Finck {
117*c2c66affSColin Finck    WRITE_SCL(LOW);
118*c2c66affSColin Finck    WRITE_SDA(LOW);
119*c2c66affSColin Finck    DELAY_HALF();
120*c2c66affSColin Finck    WRITE_SCL(HIGH);
121*c2c66affSColin Finck    DELAY_HALF();
122*c2c66affSColin Finck    WRITE_SDA(HIGH);
123*c2c66affSColin Finck }
124*c2c66affSColin Finck 
125*c2c66affSColin Finck 
126*c2c66affSColin Finck static BOOL
I2CStart(PVOID HwDeviceExtension,PI2C_CALLBACKS i2c,UCHAR Address)127*c2c66affSColin Finck I2CStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address)
128*c2c66affSColin Finck {
129*c2c66affSColin Finck    /* make sure the bus is free */
130*c2c66affSColin Finck    if (READ_SDA() == LOW || READ_SCL() == LOW)
131*c2c66affSColin Finck      {
132*c2c66affSColin Finck         WARN_(VIDEOPRT, "I2CStart: Bus is not free!\n");
133*c2c66affSColin Finck         return FALSE;
134*c2c66affSColin Finck      }
135*c2c66affSColin Finck 
136*c2c66affSColin Finck    /* send address */
137*c2c66affSColin Finck    WRITE_SDA(LOW);
138*c2c66affSColin Finck    DELAY_HALF();
139*c2c66affSColin Finck    if (!I2CWrite(HwDeviceExtension, i2c, Address))
140*c2c66affSColin Finck      {
141*c2c66affSColin Finck         /* ??release the bus?? */
142*c2c66affSColin Finck         I2CStop(HwDeviceExtension, i2c);
143*c2c66affSColin Finck         WARN_(VIDEOPRT, "I2CStart: Device not found (Address = 0x%x)\n", Address);
144*c2c66affSColin Finck         return FALSE;
145*c2c66affSColin Finck      }
146*c2c66affSColin Finck 
147*c2c66affSColin Finck    INFO_(VIDEOPRT, "I2CStart: SUCCESS!\n");
148*c2c66affSColin Finck    return TRUE;
149*c2c66affSColin Finck }
150*c2c66affSColin Finck 
151*c2c66affSColin Finck 
152*c2c66affSColin Finck static BOOL
I2CRepStart(PVOID HwDeviceExtension,PI2C_CALLBACKS i2c,UCHAR Address)153*c2c66affSColin Finck I2CRepStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address)
154*c2c66affSColin Finck {
155*c2c66affSColin Finck    /* setup lines for repeated start condition */
156*c2c66affSColin Finck    WRITE_SCL(LOW);
157*c2c66affSColin Finck    DELAY_HALF();
158*c2c66affSColin Finck    WRITE_SDA(HIGH);
159*c2c66affSColin Finck    DELAY_HALF();
160*c2c66affSColin Finck    WRITE_SCL(HIGH);
161*c2c66affSColin Finck    DELAY_HALF();
162*c2c66affSColin Finck 
163*c2c66affSColin Finck    return I2CStart(HwDeviceExtension, i2c, Address);
164*c2c66affSColin Finck }
165*c2c66affSColin Finck 
166*c2c66affSColin Finck /* PUBLIC FUNCTIONS ***********************************************************/
167*c2c66affSColin Finck 
168*c2c66affSColin Finck /*
169*c2c66affSColin Finck  * @implemented
170*c2c66affSColin Finck  */
171*c2c66affSColin Finck 
172*c2c66affSColin Finck BOOLEAN NTAPI
VideoPortDDCMonitorHelper(PVOID HwDeviceExtension,PVOID I2CFunctions,PUCHAR pEdidBuffer,ULONG EdidBufferSize)173*c2c66affSColin Finck VideoPortDDCMonitorHelper(
174*c2c66affSColin Finck    PVOID HwDeviceExtension,
175*c2c66affSColin Finck    PVOID I2CFunctions,
176*c2c66affSColin Finck    PUCHAR pEdidBuffer,
177*c2c66affSColin Finck    ULONG EdidBufferSize
178*c2c66affSColin Finck    )
179*c2c66affSColin Finck {
180*c2c66affSColin Finck    PDDC_CONTROL ddc = (PDDC_CONTROL)I2CFunctions;
181*c2c66affSColin Finck    PI2C_CALLBACKS i2c = &ddc->I2CCallbacks;
182*c2c66affSColin Finck    INT Count, i;
183*c2c66affSColin Finck    PUCHAR pBuffer = (PUCHAR)pEdidBuffer;
184*c2c66affSColin Finck    BOOL Ack;
185*c2c66affSColin Finck 
186*c2c66affSColin Finck    TRACE_(VIDEOPRT, "VideoPortDDCMonitorHelper()\n");
187*c2c66affSColin Finck 
188*c2c66affSColin Finck    ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
189*c2c66affSColin Finck    if (ddc->Size != sizeof (ddc))
190*c2c66affSColin Finck      {
191*c2c66affSColin Finck         WARN_(VIDEOPRT, "ddc->Size != %d (%d)\n", sizeof (ddc), ddc->Size);
192*c2c66affSColin Finck         return FALSE;
193*c2c66affSColin Finck      }
194*c2c66affSColin Finck 
195*c2c66affSColin Finck    /* select eeprom */
196*c2c66affSColin Finck    if (!I2CStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | WRITE))
197*c2c66affSColin Finck      return FALSE;
198*c2c66affSColin Finck    /* set address */
199*c2c66affSColin Finck    if (!I2CWrite(HwDeviceExtension, i2c, 0x00))
200*c2c66affSColin Finck      return FALSE;
201*c2c66affSColin Finck    /* change into read mode */
202*c2c66affSColin Finck    if (!I2CRepStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | READ))
203*c2c66affSColin Finck      return FALSE;
204*c2c66affSColin Finck    /* read eeprom */
205*c2c66affSColin Finck    RtlZeroMemory(pEdidBuffer, EdidBufferSize);
206*c2c66affSColin Finck    Count = min(128, EdidBufferSize);
207*c2c66affSColin Finck    for (i = 0; i < Count; i++)
208*c2c66affSColin Finck      {
209*c2c66affSColin Finck         Ack = ((i + 1) < Count);
210*c2c66affSColin Finck         pBuffer[i] = I2CRead(HwDeviceExtension, i2c, Ack);
211*c2c66affSColin Finck      }
212*c2c66affSColin Finck    I2CStop(HwDeviceExtension, i2c);
213*c2c66affSColin Finck 
214*c2c66affSColin Finck    /* check EDID header */
215*c2c66affSColin Finck    if (pBuffer[0] != 0x00 || pBuffer[1] != 0xff ||
216*c2c66affSColin Finck        pBuffer[2] != 0xff || pBuffer[3] != 0xff ||
217*c2c66affSColin Finck        pBuffer[4] != 0xff || pBuffer[5] != 0xff ||
218*c2c66affSColin Finck        pBuffer[6] != 0xff || pBuffer[7] != 0x00)
219*c2c66affSColin Finck      {
220*c2c66affSColin Finck         WARN_(VIDEOPRT, "VideoPortDDCMonitorHelper(): Invalid EDID header!\n");
221*c2c66affSColin Finck         return FALSE;
222*c2c66affSColin Finck      }
223*c2c66affSColin Finck 
224*c2c66affSColin Finck    INFO_(VIDEOPRT, "VideoPortDDCMonitorHelper(): EDID version %d rev. %d\n", pBuffer[18], pBuffer[19]);
225*c2c66affSColin Finck    INFO_(VIDEOPRT, "VideoPortDDCMonitorHelper() - SUCCESS!\n");
226*c2c66affSColin Finck    return TRUE;
227*c2c66affSColin Finck }
228