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