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