2 * Copyright 2009 Red Hat, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software")
6 * to deal in the software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * them Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * Adam Jackson <ajax@redhat.com>
26 #include "xorg-config.h"
28 #include "xf86Modes.h"
33 typedef void (*did_proc
) (int scrnIndex
, unsigned char *data
, void *closure
);
35 #define DID_PRODUCT_ID 0x00
36 #define DID_DISPLAY_PARAMETERS 0x01
37 #define DID_COLOR_INFO 0x02
38 #define DID_TIMING_1_DETAILED 0x03
39 #define DID_TIMING_2_DETAILED 0x04
40 #define DID_TIMING_3_SHORT 0x05
41 #define DID_TIMING_4_DMT 0x06
42 #define DID_TIMING_VESA 0x07
43 #define DID_TIMING_CEA 0x08
44 #define DID_TIMING_RANGE_LIMITS 0x09
45 #define DID_PRODUCT_SERIAL 0x0A
46 #define DID_ASCII_STRING 0x0B
47 #define DID_DISPLAY_DEVICE 0x0C
48 #define DID_POWER_SEQUENCING 0x0D
49 #define DID_TRANSFER_INFO 0x0E
50 #define DID_DISPLAY_INTERFACE 0x0F
51 #define DID_STEREO 0x10
52 #define DID_VENDOR 0x7F
54 #define extract_le16(x, i) ((x[i+1] << 8) + (x[i]))
55 #define extract_le24(x, i) ((x[i+2] << 16) + (x[i+1] << 8) + (x[i]))
60 return calloc(1, sizeof(DisplayModeRec
));
64 * How awesome is it to have two detailed timing formats, neither of which
65 * are compatible with the format in EDID? So awesome.
69 didDetailedTiming1(int i
, unsigned char *x
, MonPtr mon
)
71 DisplayModePtr m
= modeCalloc();
76 m
->Clock
= extract_le24(x
, 0);
78 m
->HDisplay
= extract_le16(x
, 4);
79 m
->HSyncStart
= m
->HDisplay
+ (extract_le16(x
, 8) & 0x7f);
80 m
->HSyncEnd
= m
->HSyncStart
+ extract_le16(x
, 10);
81 m
->HTotal
= m
->HDisplay
+ extract_le16(x
, 6);
82 m
->Flags
|= (x
[9] & 0x80) ? V_PHSYNC
: V_NHSYNC
;
84 m
->VDisplay
= extract_le16(x
, 12);
85 m
->VSyncStart
= m
->VDisplay
+ (extract_le16(x
, 16) & 0x7f);
86 m
->VSyncEnd
= m
->VSyncStart
+ extract_le16(x
, 18);
87 m
->VTotal
= m
->VDisplay
+ extract_le16(x
, 14);
88 m
->Flags
|= (x
[17] & 0x80) ? V_PVSYNC
: V_NVSYNC
;
92 m
->type
|= M_T_PREFERRED
;
94 /* XXX double check handling of this */
96 m
->Flags
|= V_INTERLACE
;
98 mon
->Modes
= xf86ModesAdd(mon
->Modes
, m
);
101 /* XXX no sync bits. what to do? */
103 didDetailedTiming2(int i
, unsigned char *x
, MonPtr mon
)
105 DisplayModePtr mode
= modeCalloc();
110 mode
->Clock
= extract_le24(x
, 0);
112 /* horiz sizes are in character cells, not pixels, hence * 8 */
113 mode
->HDisplay
= ((extract_le16(x
, 4) & 0x01ff) + 1) * 8;
114 mode
->HSyncStart
= mode
->HDisplay
+ (((x
[6] & 0xf0) >> 4) + 1) * 8;
115 mode
->HSyncEnd
= mode
->HSyncStart
+ ((x
[6] & 0x0f) + 1) * 8;
116 mode
->HTotal
= mode
->HDisplay
+ ((x
[5] >> 1) + 1) * 8;
118 mode
->VDisplay
= extract_le16(x
, 7) & 0x07ff;
119 mode
->VSyncStart
= mode
->VDisplay
+ (x
[10] >> 4) + 1;
120 mode
->VSyncEnd
= mode
->VSyncStart
+ (x
[10] & 0x0f) + 1;
121 mode
->VTotal
= mode
->VDisplay
+ x
[9];
123 mode
->status
= M_T_DRIVER
;
125 mode
->status
|= M_T_PREFERRED
;
127 /* XXX double check handling of this */
129 mode
->Flags
|= V_INTERLACE
;
131 mon
->Modes
= xf86ModesAdd(mon
->Modes
, mode
);
135 didShortTiming(int i
, unsigned char *x
, MonPtr mon
)
141 switch (x
[0] & 0x0f) {
163 r
= (x
[2] & 0x7f) + 1;
165 m
= xf86CVTMode(w
, h
, r
, ! !(x
[0] & 0x10), ! !(x
[2] & 0x80));
167 m
->type
= M_T_DRIVER
;
169 m
->type
|= M_T_PREFERRED
;
171 mon
->Modes
= xf86ModesAdd(mon
->Modes
, m
);
175 didDMTTiming(int i
, unsigned char *x
, void *closure
)
177 MonPtr mon
= closure
;
179 mon
->Modes
= xf86ModesAdd(mon
->Modes
, xf86DuplicateMode(DMTModes
+ *x
));
184 static const struct did_dmt
{
203 {1024, 768, 43, INT
},
209 {1024, 768, 120, RB
},
216 {1280, 768, 120, RB
},
221 {1280, 800, 120, RB
},
225 {1280, 960, 120, RB
},
229 {1280, 1024, 120, RB
},
231 {1360, 768, 120, RB
},
233 {1400, 1050, 60, RB
},
237 {1400, 1050, 120, RB
},
243 {1440, 900, 120, RB
},
249 {1600, 1200, 120, RB
},
251 {1680, 1050, 60, RB
},
255 {1680, 1050, 120, RB
},
258 {1792, 1344, 120, RB
},
262 {1856, 1392, 120, RB
},
263 {1920, 1200, 60, RB
},
267 {1920, 1200, 120, RB
},
271 {1920, 1440, 120, RB
},
272 {2560, 1600, 60, RB
},
276 {2560, 1600, 120, RB
},
280 didVesaTiming(int scrn
, unsigned char *x
, MonPtr mon
)
286 for (i
= 0; i
< 10; i
++)
287 for (j
= 0; j
< 8; j
++)
288 if (x
[i
] & (1 << j
)) {
289 const struct did_dmt
*d
= &(did_dmt
[i
* 8 + j
]);
293 mon
->Modes
= xf86ModesAdd(mon
->Modes
,
294 FindDMTMode(d
->w
, d
->h
, d
->r
,
301 handleDisplayIDBlock(int scrnIndex
, unsigned char *x
, void *closure
)
303 MonPtr mon
= closure
;
306 case DID_DISPLAY_PARAMETERS
:
307 /* w/h are in decimillimeters */
308 mon
->widthmm
= (extract_le16(x
, 3) + 5) / 10;
309 mon
->heightmm
= (extract_le16(x
, 5) + 5) / 10;
310 /* XXX pixel count, feature flags, gamma, aspect, color depth */
313 case DID_TIMING_RANGE_LIMITS
:
317 mon
->maxPixClock
= max(mon
->maxPixClock
, extract_le24(x
, 6) * 10);
321 mon
->hsync
[n
].lo
= x
[9];
322 mon
->hsync
[n
].hi
= x
[10];
327 n
= mon
->nVrefresh
++;
328 if (n
< MAX_VREFRESH
) {
329 mon
->vrefresh
[n
].lo
= x
[13];
330 mon
->vrefresh
[n
].hi
= x
[14];
338 case DID_TIMING_1_DETAILED
:
342 for (i
= 0; i
< x
[2]; i
+= 20)
343 didDetailedTiming1(scrnIndex
, x
+ i
+ 3, mon
);
347 case DID_TIMING_2_DETAILED
:
351 for (i
= 0; i
< x
[2]; i
+= 11)
352 didDetailedTiming2(scrnIndex
, x
+ i
+ 3, mon
);
356 case DID_TIMING_3_SHORT
:
360 for (i
= 0; i
< x
[2]; i
+= 3)
361 didShortTiming(scrnIndex
, x
+ i
+ 3, mon
);
365 case DID_TIMING_4_DMT
:
369 for (i
= 0; i
< x
[2]; i
++)
370 didDMTTiming(scrnIndex
, x
+ i
+ 3, mon
);
374 case DID_TIMING_VESA
:
375 didVesaTiming(scrnIndex
, x
, mon
);
378 /* XXX pixel format, ar, orientation, subpixel, dot pitch, bit depth */
379 case DID_DISPLAY_DEVICE
:
381 /* XXX interface, links, color encoding, ss, drm */
382 case DID_DISPLAY_INTERFACE
:
387 /* nothing interesting in these */
389 case DID_PRODUCT_SERIAL
:
390 case DID_ASCII_STRING
:
391 case DID_POWER_SEQUENCING
:
392 case DID_TRANSFER_INFO
:
396 /* warn about anything else */
398 xf86DrvMsg(scrnIndex
, X_WARNING
,
399 "Unknown DisplayID block type %hx\n", x
[0]);
405 forEachDisplayIDBlock(int scrnIndex
, unsigned char *did
, did_proc proc
,
408 int num_extensions
= did
[3];
409 int section_size
= did
[1];
410 unsigned char *block
;
413 if ((did
[0] & 0xf0) != 0x10) /* not 1.x, abort */
415 /* XXX also, checksum */
419 while (section_size
> 0) {
420 int block_size
= (block
[2] + 2);
422 proc(scrnIndex
, block
, closure
);
424 section_size
-= block_size
;
429 } while (num_extensions
--);
433 * Fill out MonPtr with xf86MonPtr information.
436 xf86DisplayIDMonitorSet(int scrnIndex
, MonPtr mon
, xf86MonPtr DDC
)
443 forEachDisplayIDBlock(scrnIndex
, DDC
->rawData
, handleDisplayIDBlock
, mon
);