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
VBEWriteClockLine(PVOID HwDeviceExtension,UCHAR data)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
VBEWriteDataLine(PVOID HwDeviceExtension,UCHAR data)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
VBEReadClockLine(PVOID HwDeviceExtension)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
VBEReadDataLine(PVOID HwDeviceExtension)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
VBEReadEdidUsingSCI(IN PVOID HwDeviceExtension,IN ULONG ChildIndex,OUT PVOID Edid)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
VBEReadEdid(IN PVBE_DEVICE_EXTENSION VBEDeviceExtension,IN ULONG ChildIndex,OUT PVOID Edid)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
VBEGetVideoChildDescriptor(IN PVOID HwDeviceExtension,IN PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,OUT PVIDEO_CHILD_TYPE VideoChildType,OUT PUCHAR pChildDescriptor,OUT PULONG UId,OUT PULONG pUnused)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