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 NDEBUG 25 #include <debug.h> 26 27 #define DDC_EEPROM_ADDRESS 0xA0 28 29 /* PRIVATE FUNCTIONS **********************************************************/ 30 31 #define LOW 0 32 #define HIGH 1 33 #define WRITE 0 34 #define READ 1 35 #define READ_SDA() (i2c->ReadDataLine(HwDeviceExtension)) 36 #define READ_SCL() (i2c->ReadClockLine(HwDeviceExtension)) 37 #define WRITE_SDA(state) (i2c->WriteDataLine(HwDeviceExtension, state)) 38 #define WRITE_SCL(state) (i2c->WriteClockLine(HwDeviceExtension, state)) 39 40 static LARGE_INTEGER HalfPeriodDelay = {{0, 70}}; 41 #define DELAY_HALF() KeDelayExecutionThread(KernelMode, FALSE, &HalfPeriodDelay) 42 43 44 static BOOL 45 I2CWrite(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Data) 46 { 47 UCHAR Bit; 48 BOOL Ack; 49 50 /* transmit data */ 51 for (Bit = (1 << 7); Bit != 0; Bit >>= 1) 52 { 53 WRITE_SCL(LOW); 54 WRITE_SDA((Data & Bit) ? HIGH : LOW); 55 DELAY_HALF(); 56 WRITE_SCL(HIGH); 57 DELAY_HALF(); 58 } 59 60 /* get ack */ 61 WRITE_SCL(LOW); 62 WRITE_SDA(HIGH); 63 DELAY_HALF(); 64 WRITE_SCL(HIGH); 65 do 66 { 67 DELAY_HALF(); 68 } 69 while (READ_SCL() != HIGH); 70 Ack = (READ_SDA() == LOW); 71 DELAY_HALF(); 72 73 INFO_(VIDEOPRT, "I2CWrite: %s\n", Ack ? "Ack" : "Nak"); 74 return Ack; 75 } 76 77 78 static UCHAR 79 I2CRead(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, BOOL Ack) 80 { 81 INT Bit = 0x80; 82 UCHAR Data = 0; 83 84 /* pull down SCL and release SDA */ 85 WRITE_SCL(LOW); 86 WRITE_SDA(HIGH); 87 88 /* read byte */ 89 for (Bit = (1 << 7); Bit != 0; Bit >>= 1) 90 { 91 WRITE_SCL(LOW); 92 DELAY_HALF(); 93 WRITE_SCL(HIGH); 94 DELAY_HALF(); 95 if (READ_SDA() == HIGH) 96 Data |= Bit; 97 } 98 99 /* send ack/nak */ 100 WRITE_SCL(LOW); 101 WRITE_SDA(Ack ? LOW : HIGH); 102 DELAY_HALF(); 103 WRITE_SCL(HIGH); 104 do 105 { 106 DELAY_HALF(); 107 } 108 while (READ_SCL() != HIGH); 109 110 return Data; 111 } 112 113 114 static VOID 115 I2CStop(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c) 116 { 117 WRITE_SCL(LOW); 118 WRITE_SDA(LOW); 119 DELAY_HALF(); 120 WRITE_SCL(HIGH); 121 DELAY_HALF(); 122 WRITE_SDA(HIGH); 123 } 124 125 126 static BOOL 127 I2CStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address) 128 { 129 /* make sure the bus is free */ 130 if (READ_SDA() == LOW || READ_SCL() == LOW) 131 { 132 WARN_(VIDEOPRT, "I2CStart: Bus is not free!\n"); 133 return FALSE; 134 } 135 136 /* send address */ 137 WRITE_SDA(LOW); 138 DELAY_HALF(); 139 if (!I2CWrite(HwDeviceExtension, i2c, Address)) 140 { 141 /* ??release the bus?? */ 142 I2CStop(HwDeviceExtension, i2c); 143 WARN_(VIDEOPRT, "I2CStart: Device not found (Address = 0x%x)\n", Address); 144 return FALSE; 145 } 146 147 INFO_(VIDEOPRT, "I2CStart: SUCCESS!\n"); 148 return TRUE; 149 } 150 151 152 static BOOL 153 I2CRepStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address) 154 { 155 /* setup lines for repeated start condition */ 156 WRITE_SCL(LOW); 157 DELAY_HALF(); 158 WRITE_SDA(HIGH); 159 DELAY_HALF(); 160 WRITE_SCL(HIGH); 161 DELAY_HALF(); 162 163 return I2CStart(HwDeviceExtension, i2c, Address); 164 } 165 166 /* PUBLIC FUNCTIONS ***********************************************************/ 167 168 /* 169 * @implemented 170 */ 171 172 BOOLEAN NTAPI 173 VideoPortDDCMonitorHelper( 174 PVOID HwDeviceExtension, 175 PVOID I2CFunctions, 176 PUCHAR pEdidBuffer, 177 ULONG EdidBufferSize 178 ) 179 { 180 PDDC_CONTROL ddc = (PDDC_CONTROL)I2CFunctions; 181 PI2C_CALLBACKS i2c = &ddc->I2CCallbacks; 182 INT Count, i; 183 PUCHAR pBuffer = (PUCHAR)pEdidBuffer; 184 BOOL Ack; 185 186 TRACE_(VIDEOPRT, "VideoPortDDCMonitorHelper()\n"); 187 188 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL); 189 if (ddc->Size != sizeof (ddc)) 190 { 191 WARN_(VIDEOPRT, "ddc->Size != %d (%d)\n", sizeof (ddc), ddc->Size); 192 return FALSE; 193 } 194 195 /* select eeprom */ 196 if (!I2CStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | WRITE)) 197 return FALSE; 198 /* set address */ 199 if (!I2CWrite(HwDeviceExtension, i2c, 0x00)) 200 return FALSE; 201 /* change into read mode */ 202 if (!I2CRepStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | READ)) 203 return FALSE; 204 /* read eeprom */ 205 RtlZeroMemory(pEdidBuffer, EdidBufferSize); 206 Count = min(128, EdidBufferSize); 207 for (i = 0; i < Count; i++) 208 { 209 Ack = ((i + 1) < Count); 210 pBuffer[i] = I2CRead(HwDeviceExtension, i2c, Ack); 211 } 212 I2CStop(HwDeviceExtension, i2c); 213 214 /* check EDID header */ 215 if (pBuffer[0] != 0x00 || pBuffer[1] != 0xff || 216 pBuffer[2] != 0xff || pBuffer[3] != 0xff || 217 pBuffer[4] != 0xff || pBuffer[5] != 0xff || 218 pBuffer[6] != 0xff || pBuffer[7] != 0x00) 219 { 220 WARN_(VIDEOPRT, "VideoPortDDCMonitorHelper(): Invalid EDID header!\n"); 221 return FALSE; 222 } 223 224 INFO_(VIDEOPRT, "VideoPortDDCMonitorHelper(): EDID version %d rev. %d\n", pBuffer[18], pBuffer[19]); 225 INFO_(VIDEOPRT, "VideoPortDDCMonitorHelper() - SUCCESS!\n"); 226 return TRUE; 227 } 228