1 /* 2 * ReactOS VBE EDID management 3 * 4 * Copyright (C) 2006 Herv� Poussineau 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program 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 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 */ 21 22 /* INCLUDES *******************************************************************/ 23 24 #include "vbemp.h" 25 26 /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ 27 28 static VOID NTAPI 29 VBEWriteClockLine( 30 PVOID HwDeviceExtension, 31 UCHAR data) 32 { 33 INT10_BIOS_ARGUMENTS BiosRegisters; 34 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 35 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 36 37 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 38 BiosRegisters.Eax = VBE_DDC; 39 BiosRegisters.Ebx = VBE_DDC_WRITE_SCL_CLOCK_LINE; 40 BiosRegisters.Ecx = VBEDeviceExtension->CurrentChildIndex; 41 BiosRegisters.Edx = data; 42 VBEDeviceExtension->Int10Interface.Int10CallBios( 43 VBEDeviceExtension->Int10Interface.Context, 44 &BiosRegisters); 45 } 46 47 static VOID NTAPI 48 VBEWriteDataLine( 49 PVOID HwDeviceExtension, 50 UCHAR data) 51 { 52 INT10_BIOS_ARGUMENTS BiosRegisters; 53 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 54 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 55 56 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 57 BiosRegisters.Eax = VBE_DDC; 58 BiosRegisters.Ebx = VBE_DDC_WRITE_SDA_DATA_LINE; 59 BiosRegisters.Ecx = VBEDeviceExtension->CurrentChildIndex; 60 BiosRegisters.Edx = data; 61 VBEDeviceExtension->Int10Interface.Int10CallBios( 62 VBEDeviceExtension->Int10Interface.Context, 63 &BiosRegisters); 64 } 65 66 static BOOLEAN NTAPI 67 VBEReadClockLine( 68 PVOID HwDeviceExtension) 69 { 70 INT10_BIOS_ARGUMENTS BiosRegisters; 71 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 72 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 73 74 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 75 BiosRegisters.Eax = VBE_DDC; 76 BiosRegisters.Ebx = VBE_DDC_READ_SCL_CLOCK_LINE; 77 BiosRegisters.Ecx = VBEDeviceExtension->CurrentChildIndex; 78 VBEDeviceExtension->Int10Interface.Int10CallBios( 79 VBEDeviceExtension->Int10Interface.Context, 80 &BiosRegisters); 81 82 return BiosRegisters.Edx; 83 } 84 85 static BOOLEAN NTAPI 86 VBEReadDataLine( 87 PVOID HwDeviceExtension) 88 { 89 INT10_BIOS_ARGUMENTS BiosRegisters; 90 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 91 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 92 93 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 94 BiosRegisters.Eax = VBE_DDC; 95 BiosRegisters.Ebx = VBE_DDC_READ_SDA_DATA_LINE; 96 BiosRegisters.Ecx = VBEDeviceExtension->CurrentChildIndex; 97 VBEDeviceExtension->Int10Interface.Int10CallBios( 98 VBEDeviceExtension->Int10Interface.Context, 99 &BiosRegisters); 100 101 return BiosRegisters.Edx; 102 } 103 104 static BOOLEAN 105 VBEReadEdidUsingSCI( 106 IN PVOID HwDeviceExtension, 107 IN ULONG ChildIndex, 108 OUT PVOID Edid) 109 { 110 INT10_BIOS_ARGUMENTS BiosRegisters; 111 PVBE_DEVICE_EXTENSION VBEDeviceExtension = 112 (PVBE_DEVICE_EXTENSION)HwDeviceExtension; 113 DDC_CONTROL DDCControl; 114 BOOLEAN ret; 115 116 VideoPortDebugPrint(Trace, "VBEMP: VBEReadEdidUsingSCI() called\n"); 117 118 /* 119 * Check if graphic card support I�C interface 120 */ 121 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 122 BiosRegisters.Eax = VBE_DDC; 123 BiosRegisters.Ebx = VBE_DDC_REPORT_CAPABILITIES; 124 BiosRegisters.Ecx = ChildIndex; 125 VBEDeviceExtension->Int10Interface.Int10CallBios( 126 VBEDeviceExtension->Int10Interface.Context, 127 &BiosRegisters); 128 if (VBE_GETRETURNCODE(BiosRegisters.Eax) != VBE_SUCCESS) 129 return FALSE; 130 VideoPortDebugPrint(Info, "VBEMP: VBE/SCI version %x\n", BiosRegisters.Ecx); 131 if ((BiosRegisters.Ebx & 0xF) != 0xF) 132 return FALSE; 133 134 /* 135 * Enable I�C interface 136 */ 137 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 138 BiosRegisters.Eax = VBE_DDC; 139 BiosRegisters.Ebx = VBE_DDC_BEGIN_SCL_SDA_CONTROL; 140 BiosRegisters.Ecx = ChildIndex; 141 VBEDeviceExtension->Int10Interface.Int10CallBios( 142 VBEDeviceExtension->Int10Interface.Context, 143 &BiosRegisters); 144 if (VBE_GETRETURNCODE(BiosRegisters.Eax) != VBE_SUCCESS) 145 return FALSE; 146 147 /* 148 * Read EDID information 149 */ 150 VBEDeviceExtension->CurrentChildIndex = ChildIndex; 151 DDCControl.Size = sizeof(DDC_CONTROL); 152 DDCControl.I2CCallbacks.WriteClockLine = VBEWriteClockLine; 153 DDCControl.I2CCallbacks.WriteDataLine = VBEWriteDataLine; 154 DDCControl.I2CCallbacks.ReadClockLine = VBEReadClockLine; 155 DDCControl.I2CCallbacks.ReadDataLine = VBEReadDataLine; 156 DDCControl.EdidSegment = 0; 157 ret = VideoPortDDCMonitorHelper( 158 HwDeviceExtension, 159 &DDCControl, 160 (PUCHAR)&Edid, 161 MAX_SIZE_OF_EDID); 162 163 /* 164 * Disable I�C interface 165 */ 166 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 167 BiosRegisters.Eax = VBE_DDC; 168 BiosRegisters.Ebx = VBE_DDC_END_SCL_SDA_CONTROL; 169 VBEDeviceExtension->Int10Interface.Int10CallBios( 170 VBEDeviceExtension->Int10Interface.Context, 171 &BiosRegisters); 172 /* Ignore the possible error, as we did our best to prevent problems */ 173 174 return ret; 175 } 176 177 static BOOLEAN 178 VBEReadEdid( 179 IN PVBE_DEVICE_EXTENSION VBEDeviceExtension, 180 IN ULONG ChildIndex, 181 OUT PVOID Edid) 182 { 183 INT10_BIOS_ARGUMENTS BiosRegisters; 184 185 VideoPortDebugPrint(Trace, "VBEMP: VBEReadEdid() called\n"); 186 187 /* 188 * Check if DDC1/DDC2 is supported 189 */ 190 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 191 BiosRegisters.Eax = VBE_DDC; 192 VBEDeviceExtension->Int10Interface.Int10CallBios( 193 VBEDeviceExtension->Int10Interface.Context, 194 &BiosRegisters); 195 if (VBE_GETRETURNCODE(BiosRegisters.Eax) != VBE_SUCCESS) 196 return FALSE; 197 if ((BiosRegisters.Ebx & 3) == 0) 198 return FALSE; 199 200 /* 201 * Directly read EDID information 202 */ 203 VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters)); 204 BiosRegisters.Eax = VBE_DDC; 205 BiosRegisters.Ebx = VBE_DDC_READ_EDID; 206 BiosRegisters.Ecx = ChildIndex; 207 BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset; 208 BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment; 209 VBEDeviceExtension->Int10Interface.Int10CallBios( 210 VBEDeviceExtension->Int10Interface.Context, 211 &BiosRegisters); 212 213 if (VBE_GETRETURNCODE(BiosRegisters.Eax) != VBE_SUCCESS) 214 return FALSE; 215 216 /* 217 * Copy the EDID information to our buffer 218 */ 219 VBEDeviceExtension->Int10Interface.Int10ReadMemory( 220 VBEDeviceExtension->Int10Interface.Context, 221 VBEDeviceExtension->TrampolineMemorySegment, 222 VBEDeviceExtension->TrampolineMemoryOffset, 223 Edid, 224 MAX_SIZE_OF_EDID); 225 226 return TRUE; 227 } 228 229 VP_STATUS NTAPI 230 VBEGetVideoChildDescriptor( 231 IN PVOID HwDeviceExtension, 232 IN PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, 233 OUT PVIDEO_CHILD_TYPE VideoChildType, 234 OUT PUCHAR pChildDescriptor, 235 OUT PULONG UId, 236 OUT PULONG pUnused) 237 { 238 if (ChildEnumInfo->Size != sizeof(VIDEO_CHILD_ENUM_INFO) || 239 ChildEnumInfo->ChildDescriptorSize < MAX_SIZE_OF_EDID) 240 { 241 return ERROR_INVALID_FUNCTION; 242 } 243 244 if (ChildEnumInfo->ChildIndex == 0) 245 { 246 /* We don't support enumeration of ACPI children */ 247 return ERROR_NO_MORE_DEVICES; 248 } 249 else if (ChildEnumInfo->ChildIndex == 1) 250 { 251 /* Our screen */ 252 *VideoChildType = Monitor; 253 *UId = 1; 254 255 /* Try to read EDID information using 2 different methods. */ 256 if (VBEReadEdid(HwDeviceExtension, 0, pChildDescriptor)) 257 { 258 VideoPortDebugPrint(Info, "VBEMP: EDID information read directly\n"); 259 } 260 else if (VBEReadEdidUsingSCI(HwDeviceExtension, 0, pChildDescriptor)) 261 { 262 VideoPortDebugPrint(Info, "VBEMP: EDID information read using I2C\n"); 263 } 264 265 return VIDEO_ENUM_MORE_DEVICES; 266 } 267 else 268 { 269 /* Unknown hardware id */ 270 return ERROR_NO_MORE_DEVICES; 271 } 272 } 273