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