xref: /reactos/win32ss/drivers/miniport/vbe/edid.c (revision 983d9a1c)
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