source: trunk/third/read-edid/parse-edid.c @ 15067

Revision 15067, 8.3 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15066, which included commits to RCS files with non-trunk default branches.
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5typedef unsigned char byte;
6/* byte must be 8 bits */
7
8/* int must be at least 16 bits */
9
10/* long must be at least 32 bits */
11
12
13
14#define DIE_MSG( x ) \
15        { MSG( x ); exit( 1 ); }
16
17
18#define UPPER_NIBBLE( x ) \
19        (((128|64|32|16) & (x)) >> 4)
20
21#define LOWER_NIBBLE( x ) \
22        ((1|2|4|8) & (x))
23
24#define COMBINE_HI_8LO( hi, lo ) \
25        ( (((unsigned)hi) << 8) | (unsigned)lo )
26
27#define COMBINE_HI_4LO( hi, lo ) \
28        ( (((unsigned)hi) << 4) | (unsigned)lo )
29
30const byte edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
31                                0xff, 0xff, 0xff, 0x00 };
32
33const byte edid_v1_descriptor_flag[] = { 0x00, 0x00 };
34
35
36#define EDID_LENGTH                             0x80
37
38#define EDID_HEADER                             0x00
39#define EDID_HEADER_END                         0x07
40
41#define ID_MANUFACTURER_NAME                    0x08
42#define ID_MANUFACTURER_NAME_END                0x09
43
44#define EDID_STRUCT_VERSION                     0x12
45#define EDID_STRUCT_REVISION                    0x13
46
47#define ESTABLISHED_TIMING_1                    0x23
48#define ESTABLISHED_TIMING_2                    0x24
49#define MANUFACTURERS_TIMINGS                   0x25
50
51#define DETAILED_TIMING_DESCRIPTIONS_START      0x36
52#define DETAILED_TIMING_DESCRIPTION_SIZE        18
53#define NO_DETAILED_TIMING_DESCRIPTIONS         4
54
55
56
57#define DETAILED_TIMING_DESCRIPTION_1           0x36
58#define DETAILED_TIMING_DESCRIPTION_2           0x48
59#define DETAILED_TIMING_DESCRIPTION_3           0x5a
60#define DETAILED_TIMING_DESCRIPTION_4           0x6c
61
62
63
64#define PIXEL_CLOCK_LO     (unsigned)dtd[ 0 ]
65#define PIXEL_CLOCK_HI     (unsigned)dtd[ 1 ]
66#define PIXEL_CLOCK        (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000)
67
68#define H_ACTIVE_LO        (unsigned)dtd[ 2 ]
69
70#define H_BLANKING_LO      (unsigned)dtd[ 3 ]
71
72#define H_ACTIVE_HI        UPPER_NIBBLE( (unsigned)dtd[ 4 ] )
73
74#define H_ACTIVE           COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
75
76#define H_BLANKING_HI      LOWER_NIBBLE( (unsigned)dtd[ 4 ] )
77
78#define H_BLANKING         COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
79
80
81
82
83#define V_ACTIVE_LO        (unsigned)dtd[ 5 ]
84
85#define V_BLANKING_LO      (unsigned)dtd[ 6 ]
86
87#define V_ACTIVE_HI        UPPER_NIBBLE( (unsigned)dtd[ 7 ] )
88
89#define V_ACTIVE           COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
90
91#define V_BLANKING_HI      LOWER_NIBBLE( (unsigned)dtd[ 7 ] )
92
93#define V_BLANKING         COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
94
95
96
97#define H_SYNC_OFFSET_LO   (unsigned)dtd[ 8 ]
98#define H_SYNC_WIDTH_LO    (unsigned)dtd[ 9 ]
99
100#define V_SYNC_OFFSET_LO   UPPER_NIBBLE( (unsigned)dtd[ 10 ] )
101#define V_SYNC_WIDTH_LO    LOWER_NIBBLE( (unsigned)dtd[ 10 ] )
102
103#define V_SYNC_WIDTH_HI    ((unsigned)dtd[ 11 ] & (1|2))
104#define V_SYNC_OFFSET_HI   (((unsigned)dtd[ 11 ] & (4|8)) >> 2)
105
106#define H_SYNC_WIDTH_HI    (((unsigned)dtd[ 11 ] & (16|32)) >> 4)
107#define H_SYNC_OFFSET_HI   (((unsigned)dtd[ 11 ] & (64|128)) >> 6)
108
109
110#define V_SYNC_WIDTH       COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
111#define V_SYNC_OFFSET      COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
112
113#define H_SYNC_WIDTH       COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
114#define H_SYNC_OFFSET      COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
115
116#define H_SIZE_LO          (unsigned)dtd[ 12 ]
117#define V_SIZE_LO          (unsigned)dtd[ 13 ]
118
119#define H_SIZE_HI          UPPER_NIBBLE( (unsigned)dtd[ 14 ] )
120#define V_SIZE_HI          LOWER_NIBBLE( (unsigned)dtd[ 14 ] )
121
122#define H_SIZE             COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
123#define V_SIZE             COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
124
125#define H_BORDER           (unsigned)dtd[ 15 ]
126#define V_BORDER           (unsigned)dtd[ 16 ]
127
128#define FLAGS              (unsigned)dtd[ 17 ]
129
130#define INTERLACED         (FLAGS&128)
131
132
133#define MONITOR_NAME            0xfc
134#define MONITOR_LIMITS          0xfd
135#define UNKNOWN_DESCRIPTOR      -1
136#define DETAILED_TIMING_BLOCK   -2
137
138
139#define DESCRIPTOR_DATA         5
140#define V_MIN_RATE              block[ 5 ]
141#define V_MAX_RATE              block[ 6 ]
142#define H_MIN_RATE              block[ 7 ]
143#define H_MAX_RATE              block[ 8 ]
144
145#define MAX_PIXEL_CLOCK         (((int)block[ 9 ]) * 10)
146#define GTF_SUPPORT             block[10]
147
148char* myname;
149
150void MSG( const char* x )
151{
152  fprintf( stderr, "%s: %s\n", myname, x );
153}
154
155
156int
157parse_edid( byte* edid );
158
159
160int
161parse_timing_description( byte* dtd );
162
163
164int
165parse_monitor_limits( byte* block );
166
167int
168block_type( byte* block );
169
170char*
171get_monitor_name( byte const*  block );
172
173
174int
175main( int argc, char** argv )
176{
177  byte edid[ EDID_LENGTH ];
178  FILE* edid_file;
179
180  myname = argv[ 0 ];
181  fprintf( stderr, "%s: parse-edid version 1.3.7\n", myname );
182 
183  if ( argc > 2 )
184    {
185      DIE_MSG( "syntax: [input EDID file]" );
186    }
187  else
188    {
189      if ( argc == 2 )
190        {
191          edid_file = fopen( argv[ 1 ], "rb" );
192          if ( !edid_file )
193            DIE_MSG( "unable to open file for input\n" );
194        }
195     
196      else
197        edid_file = stdin;
198    }
199
200  if ( fread( edid, sizeof( byte ), EDID_LENGTH, edid_file )
201       != EDID_LENGTH )
202
203    {
204      DIE_MSG( "IO error reading EDID" );
205    }
206
207  fclose( edid_file );
208
209  return parse_edid( edid );
210}
211
212int
213parse_edid( byte* edid )
214{
215  unsigned i;
216  byte* block;
217  char* monitor_name = "Unknown";
218  byte checksum = 0;
219 
220  for( i = 0; i < EDID_LENGTH; i++ )
221    checksum += edid[ i ];
222
223  if (  checksum != 0  )
224      MSG( "EDID checksum failed - data is corrupt. Continuing anyway." );
225  else
226      MSG( "EDID checksum passed." );
227 
228
229  if ( strncmp( edid+EDID_HEADER, edid_v1_header, EDID_HEADER_END+1 ) )
230    {
231      MSG( "first bytes don't match EDID version 1 header" );
232      MSG( "do not trust output (if any)." );
233    }
234
235  printf( "\n# EDID version %d revision %d\n", (int)edid[EDID_STRUCT_VERSION],(int)edid[EDID_STRUCT_REVISION] );
236 
237
238  printf( "Section \"Monitor\"\n" );
239
240  block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
241
242  for( i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS; i++,
243         block += DETAILED_TIMING_DESCRIPTION_SIZE )
244    {
245
246      if ( block_type( block ) == MONITOR_NAME )
247        {
248          monitor_name = get_monitor_name( block );
249          break;
250        }
251    }
252
253  printf( "\tIdentifier \"%s\"\n", monitor_name );
254  printf( "\tVendorName \"Unknown\"\n" );
255  printf( "\tModelName \"%s\"\n", monitor_name );
256
257
258  block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
259
260  for( i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS; i++,
261         block += DETAILED_TIMING_DESCRIPTION_SIZE )
262    {
263
264      if ( block_type( block ) == MONITOR_LIMITS )
265        parse_monitor_limits( block );
266    }
267
268
269  block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
270
271  for( i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS; i++,
272         block += DETAILED_TIMING_DESCRIPTION_SIZE )
273    {
274
275      if ( block_type( block ) == DETAILED_TIMING_BLOCK )
276        parse_timing_description( block );
277    }
278
279
280  printf( "EndSection\n" );
281
282  return 0;
283}
284
285
286int
287parse_timing_description( byte* dtd )
288{
289  printf( "\tMode \t\"%dx%d\"\n", H_ACTIVE, V_ACTIVE );
290
291  printf( "\t\tDotClock\t%f\n", (double)PIXEL_CLOCK/1000000.0 );
292
293  printf( "\t\tHTimings\t%u %u %u %u\n", H_ACTIVE,
294          H_ACTIVE+H_SYNC_OFFSET,
295          H_ACTIVE+H_SYNC_OFFSET+H_SYNC_WIDTH,
296          H_ACTIVE+H_BLANKING );
297
298  printf( "\t\tVTimings\t%u %u %u %u\n", V_ACTIVE,
299          V_ACTIVE+V_SYNC_OFFSET,
300          V_ACTIVE+V_SYNC_OFFSET+V_SYNC_WIDTH,
301          V_ACTIVE+V_BLANKING );
302
303  if ( INTERLACED )
304    printf( "\t\tFlags\t\"Interlace\"\n" );
305
306  printf( "\tEndMode\n" );
307
308  return 0;
309}
310
311
312int
313block_type( byte* block )
314{
315
316  if ( !strncmp( edid_v1_descriptor_flag, block, 2 ) )
317    {
318
319      /* descriptor */
320
321      if ( block[ 2 ] != 0 )
322        return UNKNOWN_DESCRIPTOR;
323
324
325      return block[ 3 ];
326    } else {
327
328      /* detailed timing block */
329
330      return DETAILED_TIMING_BLOCK;
331    }
332}
333
334char*
335get_monitor_name( byte const* block )
336{
337  static char name[ 13 ];
338  unsigned i;
339  byte const* ptr = block + DESCRIPTOR_DATA;
340
341
342  for( i = 0; i < 13; i++, ptr++ )
343    {
344
345      if ( *ptr == 0xa )
346        {
347          name[ i ] = 0;
348          return name;
349        }
350
351      name[ i ] = *ptr;
352    }
353
354
355  return name;
356}
357
358int
359parse_monitor_limits( byte* block )
360{
361  printf( "\tHorizSync %u-%u\n", H_MIN_RATE, H_MAX_RATE );
362  printf( "\tVertRefresh %u-%u\n", V_MIN_RATE, V_MAX_RATE );
363  if ( MAX_PIXEL_CLOCK == 10*0xff )
364    printf( "# Max dot clock not given\n" );
365  else
366    printf( "# Max dot clock (video bandwidth) %u MHz\n", (int)MAX_PIXEL_CLOCK );
367
368  if ( GTF_SUPPORT )
369    {
370      printf( "# EDID version 3 GTF given: contact author\n" );
371    }
372 
373  return 0;
374}
375
Note: See TracBrowser for help on using the repository browser.