2 # dtd_parser.py - DTD structure parser
4 # SPDX-License-Identifier: GPL-2.0-only
7 DTD string parser/generator.
9 Detailed timing descriptor (DTD) is an 18 byte array describing video mode
10 (screen resolution, display properties, etc.) in EDID and used by Intel Option
11 ROM. Option ROM can support multiple video modes, specific mode is picked by
12 the BIOS through the appropriate Option ROM callback function.
14 This program allows to interpret the 18 byte hex DTD dump, and/or modify
15 certain values and generate a new DTD.
21 # The DTD array format description can be found in
22 # http://en.wikipedia.org/wiki/Extended_display_identification_data, (see the
23 # EDID Detailed Timing Descriptor section).
25 # The below dictionary describes how different DTD parameters are laid out in
26 # the array. Note that many parameters span multiple bit fields in the DTD.
28 # The keys in the dictionary are stings (field names), the values are tuples
29 # of either numbers or tri-tuples. If the element of the tuple is a number, it
30 # is the offset in DTD, and the entire byte is used in this field. If the
31 # element is a tri-tuple, its components are (DTD offset, bit shift, field
34 # The partial values are extracted from the DTD fields and concatenated
35 # together to form actual parameter value.
40 'hor_active' : ((4, 4, 4), 2),
41 'hor_blank' : ((4, 0, 4), 3),
42 'vert_act' : ((7, 4, 4), 5),
43 'vert_blank' : ((7, 0, 4), 6),
44 'hsync_offset' : ((11, 6, 2), 8),
45 'hsync_pulse_width' : ((11, 4, 2), 9),
46 'vsync_offset' : ((11, 2, 2), (10, 4, 4)),
47 'vsync_pulse_width' : ((11, 0, 2), (10, 0, 4)),
48 'hor_image_size' : ((14, 4, 4), 12),
49 'vert_image_size' : ((14, 0, 4), 13),
51 'vert_border' : (16,),
52 'interlaced' : ((17, 7, 1),),
53 'reserved' : ((17, 5, 2), (17, 0, 1)),
54 'digital_separate' : ((17, 3, 2),),
55 'vert_polarity' : ((17, 2, 1),),
56 'hor_polarity' : ((17, 1, 1),),
62 '''An object containing all DTD information.
64 The attributes are created dynamically when the input DTD string is
65 parsed. For each element of the above dictionary two attributes are added:
67 'attr_<param>' to hold the actual parameter value
68 'max_attr_<param>' to hold the maximum allowed value for this parameter.
72 for name
in dtd_descriptor
:
73 setattr(self
, PREFIX
+ name
, 0)
75 def init(self
, sarray
):
76 '''Initialize the object with values from a DTD array.
80 sarray: a string, an array of ASCII hex representations of the 18 DTD
83 Raises: implicitly raises ValueError or IndexError exceptions in case
84 the input string has less than 18 elements, or some of the
85 elements can not be converted to integer.
88 harray
= [int(x
, 16) for x
in sarray
]
89 for name
, desc
in dtd_descriptor
.iteritems():
93 if isinstance(tup
, tuple):
94 offset
, shift
, width
= tup
96 offset
, shift
, width
= tup
, 0, 8
98 mask
= (1 << width
) - 1
99 attr_value
= (attr_value
<< width
) + (
100 (harray
[offset
] >> shift
) & mask
)
102 setattr(self
, PREFIX
+ name
, attr_value
)
103 setattr(self
, 'max_' + PREFIX
+ name
, (1 << total_width
) - 1)
107 for name
in sorted(dtd_descriptor
.keys()):
108 text
.append('%20s: %d' % (name
, getattr(self
, PREFIX
+ name
)))
109 return '\n'.join(text
)
112 '''Generate contents of the DTD as a 18 byte ASCII hex array.'''
115 for name
, desc
in dtd_descriptor
.iteritems():
116 attr_value
= getattr(self
, PREFIX
+ name
)
120 if isinstance(tup
, tuple):
121 offset
, shift
, width
= tup
123 offset
, shift
, width
= tup
, 0, 8
125 mask
= (1 << width
) - 1
126 value
= attr_value
& mask
127 attr_value
= attr_value
>> width
128 result
[offset
] = (result
[offset
] & ~
(
129 mask
<< shift
)) |
(value
<< shift
)
131 return ' '.join('%2.2x' % x
for x
in result
)
133 def handle_input(self
, name
):
134 '''Get user input and set a new parameter value if required.
136 Display the parameter name, its current value, and prompt user for a
139 If the user enters a dot, stop processing (return True).
141 Empty user input means that this parameter does not have to change,
142 but the next parameter should be prompted.
144 If input is non-empty, it is interpreted as a hex number, checked if
145 it fits the parameter and the new parameter value is set if checks
150 name - a string, parameter name, a key in dtd_descriptor
154 Boolean, True meaning no more field are required to be modified, False
155 meaning that more field mods need to be prompted..
158 param
= PREFIX
+ name
159 vmax
= getattr(self
, 'max_' + param
)
160 new_value
= raw_input('%s : %d ' % (name
, getattr(self
, param
)))
165 new_int
= int(new_value
)
167 print '%s exceeds maximum for %s (%d)' % (new_value
, name
, vmax
)
169 setattr(self
, param
, new_int
)
183 for line
in str(d
).splitlines():
184 if d
.handle_input(line
.split(':')[0].strip()):
191 if __name__
== '__main__':
194 except (ValueError, IndexError):
196 A string of 18 byte values in hex is required.
197 '-m' preceding the string will allow setting new parameter values.