blob: 83e9cf6dec52130f35b4c03984d04b072eca1aea [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2016 secunet Security Networks AG
3--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with HW;
16
17with HW.Debug;
18with GNAT.Source_Info;
19
20use type HW.Byte;
21use type HW.Pos16;
22use type HW.Word16;
23
24package body HW.GFX.EDID is
25
Nico Huber88a7f172016-11-18 21:19:46 +010026 subtype Header_Index is Raw_EDID_Index range 0 .. 7;
27 type Header_Type is new Buffer (Header_Index);
28 Header_Pattern : constant Header_Type :=
29 (16#00#, 16#ff#, 16#ff#, 16#ff#, 16#ff#, 16#ff#, 16#ff#, 16#00#);
30
Nico Huber83693c82016-10-08 22:17:55 +020031 function Checksum_Valid (Raw_EDID : Raw_EDID_Data) return Boolean
32 with
33 Pre => True
34 is
35 Sum : Byte := 16#00#;
36 begin
37 for I in Raw_EDID_Index loop
38 Sum := Sum + Raw_EDID (I);
39 end loop;
40 pragma Debug (Sum /= 16#00#, Debug.Put_Line
41 (GNAT.Source_Info.Enclosing_Entity & ": EDID checksum invalid!"));
42 return Sum = 16#00#;
43 end Checksum_Valid;
44
Nico Huber88a7f172016-11-18 21:19:46 +010045 function Header_Score (Raw_EDID : Raw_EDID_Data) return Natural
46 is
47 Score : Natural := 0;
48 begin
49 for I in Header_Index loop
50 pragma Loop_Invariant (Score <= I);
51 if Raw_EDID (I) = Header_Pattern (I) then
52 Score := Score + 1;
53 end if;
54 end loop;
55 return Score;
56 end Header_Score;
57
Nico Huber83693c82016-10-08 22:17:55 +020058 function Valid (Raw_EDID : Raw_EDID_Data) return Boolean
59 is
Nico Huber83693c82016-10-08 22:17:55 +020060 begin
Nico Huber88a7f172016-11-18 21:19:46 +010061 return Header_Score (Raw_EDID) = 8 and then Checksum_Valid (Raw_EDID);
62 end Valid;
63
64 procedure Sanitize (Raw_EDID : in out Raw_EDID_Data; Success : out Boolean)
65 is
66 Score : constant Natural := Header_Score (Raw_EDID);
67 begin
68 pragma Debug (Score /= 8, Debug.Put_Line
Nico Huber83693c82016-10-08 22:17:55 +020069 (GNAT.Source_Info.Enclosing_Entity & ": EDID header pattern mismatch!"));
70
Nico Huber88a7f172016-11-18 21:19:46 +010071 if Score = 6 or Score = 7 then
72 pragma Debug (Debug.Put_Line
73 (GNAT.Source_Info.Enclosing_Entity & ": Trying to fix up."));
74 Raw_EDID (Header_Index) := Buffer (Header_Pattern);
75 end if;
76
77 Success := Valid (Raw_EDID);
78 end Sanitize;
Nico Huber83693c82016-10-08 22:17:55 +020079
80 ----------------------------------------------------------------------------
81
82 REVISION : constant := 19;
83 INPUT : constant := 20;
84 INPUT_DIGITAL : constant := 1 * 2 ** 7;
85 INPUT_DIGITAL_DEPTH_SHIFT : constant := 4;
86 INPUT_DIGITAL_DEPTH_MASK : constant := 7 * 2 ** 4;
87 INPUT_DIGITAL_DEPTH_UNDEF : constant := 0 * 2 ** 4;
88 INPUT_DIGITAL_DEPTH_RESERVED : constant := 7 * 2 ** 4;
89
90 ----------------------------------------------------------------------------
91
Nico Huber393aa8a2016-10-21 14:18:53 +020092 function Compatible_Display
93 (Raw_EDID : Raw_EDID_Data;
94 Display : Display_Type)
95 return Boolean
96 is
97 begin
98 return (Display = VGA) = ((Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00#);
99 end Compatible_Display;
100
Nico Huber83693c82016-10-08 22:17:55 +0200101 function Read_LE16
102 (Raw_EDID : Raw_EDID_Data;
103 Offset : Raw_EDID_Index)
104 return Word16
105 is
106 begin
107 return Shift_Left (Word16 (Raw_EDID (Offset + 1)), 8) or
108 Word16 (Raw_EDID (Offset));
109 end Read_LE16;
110
Nico Huber83693c82016-10-08 22:17:55 +0200111 function Preferred_Mode (Raw_EDID : Raw_EDID_Data) return Mode_Type
112 is
113 Base : constant := DESCRIPTOR_1;
114 Mode : Mode_Type;
115
116 function Read_12
117 (Lower_8, Upper_4 : Raw_EDID_Index;
118 Shift : Natural)
Nico Huber7eb13502018-06-04 14:42:13 +0200119 return Word16 is
120 ( Word16 (Raw_EDID (Lower_8)) or
121 (Shift_Left (Word16 (Raw_EDID (Upper_4)), Shift) and 16#0f00#));
Nico Huber83693c82016-10-08 22:17:55 +0200122
123 function Read_10
124 (Lower_8, Upper_2 : Raw_EDID_Index;
125 Shift : Natural)
Nico Huber7eb13502018-06-04 14:42:13 +0200126 return Word16 is
127 ( Word16 (Raw_EDID (Lower_8)) or
128 (Shift_Left (Word16 (Raw_EDID (Upper_2)), Shift) and 16#0300#));
Nico Huber83693c82016-10-08 22:17:55 +0200129
130 function Read_6
131 (Lower_4 : Raw_EDID_Index;
132 Lower_Shift : Natural;
133 Upper_2 : Raw_EDID_Index;
134 Upper_Shift : Natural)
Nico Huber7eb13502018-06-04 14:42:13 +0200135 return Word8 is
136 ((Shift_Right (Word8 (Raw_EDID (Lower_4)), Lower_Shift) and 16#0f#) or
137 (Shift_Left (Word8 (Raw_EDID (Upper_2)), Upper_Shift) and 16#30#));
Nico Huber83693c82016-10-08 22:17:55 +0200138 begin
139 Mode := Mode_Type'
140 (Dotclock => Pos64 (Read_LE16 (Raw_EDID, Base)) * 10_000,
141 H_Visible => Pos16 (Read_12 (Base + 2, Base + 4, 4)),
142 H_Sync_Begin => Pos16 (Read_10 (Base + 8, Base + 11, 2)),
143 H_Sync_End => Pos16 (Read_10 (Base + 9, Base + 11, 4)),
144 H_Total => Pos16 (Read_12 (Base + 3, Base + 4, 8)),
145 V_Visible => Pos16 (Read_12 (Base + 5, Base + 7, 4)),
146 V_Sync_Begin => Pos16 (Read_6 (Base + 10, 4, Base + 11, 2)),
147 V_Sync_End => Pos16 (Read_6 (Base + 10, 0, Base + 11, 4)),
148 V_Total => Pos16 (Read_12 (Base + 6, Base + 7, 8)),
149 H_Sync_Active_High => (Raw_EDID (Base + 17) and 16#02#) /= 0,
150 V_Sync_Active_High => (Raw_EDID (Base + 17) and 16#04#) /= 0,
151 BPC =>
152 (if Raw_EDID (REVISION) < 4 or
153 (Raw_EDID (INPUT) and INPUT_DIGITAL) = 16#00# or
154 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_UNDEF or
155 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK) = INPUT_DIGITAL_DEPTH_RESERVED
156 then
Nico Huber16f3dec2016-10-09 19:33:34 +0200157 Auto_BPC
Nico Huber83693c82016-10-08 22:17:55 +0200158 else
159 4 + 2 * Pos64 (Shift_Right
160 (Raw_EDID (INPUT) and INPUT_DIGITAL_DEPTH_MASK,
161 INPUT_DIGITAL_DEPTH_SHIFT))));
162
163 -- Calculate absolute values from EDID relative values.
164 Mode.H_Sync_Begin := Mode.H_Visible + Mode.H_Sync_Begin;
165 Mode.H_Sync_End := Mode.H_Sync_Begin + Mode.H_Sync_End;
166 Mode.H_Total := Mode.H_Visible + Mode.H_Total;
167 Mode.V_Sync_Begin := Mode.V_Visible + Mode.V_Sync_Begin;
168 Mode.V_Sync_End := Mode.V_Sync_Begin + Mode.V_Sync_End;
169 Mode.V_Total := Mode.V_Visible + Mode.V_Total;
170
171 return Mode;
172 end Preferred_Mode;
173
174end HW.GFX.EDID;