Rev 1029 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1029 | serge | 1 | /* |
2 | * Copyright 2007, 2008 Luc Verhaegen |
||
3 | * Copyright 2007, 2008 Matthias Hopf |
||
4 | * Copyright 2007, 2008 Egbert Eich |
||
5 | * Copyright 2007, 2008 Advanced Micro Devices, Inc. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the "Software"), |
||
9 | * to deal in the Software without restriction, including without limitation |
||
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
11 | * and/or sell copies of the Software, and to permit persons to whom the |
||
12 | * Software is furnished to do so, subject to the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice shall be included in |
||
15 | * all copies or substantial portions of the Software. |
||
16 | * |
||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
20 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
23 | * OTHER DEALINGS IN THE SOFTWARE. |
||
24 | */ |
||
25 | #define _PARSE_EDID_ |
||
26 | |||
27 | #include "common.h" |
||
28 | #include "rhd.h" |
||
29 | |||
30 | #include "edid.h" |
||
31 | |||
32 | #include "xf86DDC.h" |
||
33 | |||
34 | #include "rhd_connector.h" |
||
35 | #include "rhd_modes.h" |
||
36 | #include "rhd_monitor.h" |
||
37 | #ifdef ATOM_BIOS |
||
38 | # include "rhd_atombios.h" |
||
39 | #endif |
||
40 | |||
41 | /* From rhd_edid.c */ |
||
42 | void RHDMonitorEDIDSet(struct rhdMonitor *Monitor, xf86MonPtr EDID); |
||
43 | |||
44 | |||
45 | /* |
||
46 | * |
||
47 | */ |
||
48 | |||
49 | void |
||
50 | RHDMonitorPrint(struct rhdMonitor *Monitor) |
||
51 | { |
||
52 | int i; |
||
53 | |||
54 | xf86Msg(X_NONE, " Bandwidth: %dMHz\n", Monitor->Bandwidth / 1000); |
||
55 | xf86Msg(X_NONE, " Horizontal timing:\n"); |
||
56 | for (i = 0; i < Monitor->numHSync; i++) |
||
57 | xf86Msg(X_NONE, " %3.1f - %3.1fkHz\n", Monitor->HSync[i].lo, |
||
58 | Monitor->HSync[i].hi); |
||
59 | xf86Msg(X_NONE, " Vertical timing:\n"); |
||
60 | for (i = 0; i < Monitor->numVRefresh; i++) |
||
61 | xf86Msg(X_NONE, " %3.1f - %3.1fHz\n", Monitor->VRefresh[i].lo, |
||
62 | Monitor->VRefresh[i].hi); |
||
63 | xf86Msg(X_NONE, " DPI: %dx%d\n", Monitor->xDpi, Monitor->yDpi); |
||
64 | if (Monitor->ReducedAllowed) |
||
65 | xf86Msg(X_NONE, " Allows reduced blanking.\n"); |
||
66 | if (Monitor->UseFixedModes) |
||
67 | xf86Msg(X_NONE, " Uses Fixed Modes.\n"); |
||
68 | |||
69 | if (!Monitor->Modes) |
||
70 | xf86Msg(X_NONE, " No modes are provided.\n"); |
||
71 | else { |
||
72 | DisplayModePtr Mode; |
||
73 | |||
74 | xf86Msg(X_NONE, " Attached modes:\n"); |
||
75 | for (Mode = Monitor->Modes; Mode; Mode = Mode->next) { |
||
76 | xf86Msg(X_NONE, " "); |
||
77 | RHDPrintModeline(Mode); |
||
78 | } |
||
79 | } |
||
80 | } |
||
81 | |||
82 | |||
83 | #if 0 |
||
84 | |||
85 | /* |
||
86 | * |
||
87 | */ |
||
88 | static struct rhdMonitor * |
||
89 | rhdMonitorFromConfig(int scrnIndex, MonPtr Config) |
||
90 | { |
||
91 | struct rhdMonitor *Monitor; |
||
92 | DisplayModePtr Mode; |
||
93 | int i; |
||
94 | |||
95 | Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); |
||
96 | |||
97 | Monitor->Name = xnfstrdup(Config->id); |
||
98 | Monitor->scrnIndex = scrnIndex; |
||
99 | |||
100 | if (Config->nHsync) { |
||
101 | Monitor->numHSync = Config->nHsync; |
||
102 | for (i = 0; i < Config->nHsync; i++) { |
||
103 | Monitor->HSync[i].lo = Config->hsync[i].lo; |
||
104 | Monitor->HSync[i].hi = Config->hsync[i].hi; |
||
105 | } |
||
106 | } else if (!Monitor->numHSync) { |
||
107 | Monitor->numHSync = 3; |
||
108 | Monitor->HSync[0].lo = 31.5; |
||
109 | Monitor->HSync[0].hi = 31.5; |
||
110 | Monitor->HSync[1].lo = 35.15; |
||
111 | Monitor->HSync[1].hi = 35.15; |
||
112 | Monitor->HSync[2].lo = 35.5; |
||
113 | Monitor->HSync[2].hi = 35.5; |
||
114 | } |
||
115 | |||
116 | if (Config->nVrefresh) { |
||
117 | Monitor->numVRefresh = Config->nVrefresh; |
||
118 | for (i = 0; i < Config->nVrefresh; i++) { |
||
119 | Monitor->VRefresh[i].lo = Config->vrefresh[i].lo; |
||
120 | Monitor->VRefresh[i].hi = Config->vrefresh[i].hi; |
||
121 | } |
||
122 | } else if (!Monitor->numVRefresh) { |
||
123 | Monitor->numVRefresh = 1; |
||
124 | Monitor->VRefresh[0].lo = 50; |
||
125 | Monitor->VRefresh[0].hi = 61; |
||
126 | } |
||
127 | |||
128 | #ifdef MONREC_HAS_REDUCED |
||
129 | if (Config->reducedblanking) |
||
130 | Monitor->ReducedAllowed = TRUE; |
||
131 | #endif |
||
132 | |||
133 | #ifdef MONREC_HAS_BANDWIDTH |
||
134 | if (Config->maxPixClock) |
||
135 | Monitor->Bandwidth = Config->maxPixClock; |
||
136 | #endif |
||
137 | |||
138 | for (Mode = Config->Modes; Mode; Mode = Mode->next) |
||
139 | Monitor->Modes = RHDModesAdd(Monitor->Modes, RHDModeCopy(Mode)); |
||
140 | |||
141 | return Monitor; |
||
142 | } |
||
143 | #endif |
||
144 | |||
145 | /* |
||
146 | * |
||
147 | */ |
||
148 | static struct rhdMonitor * |
||
149 | rhdMonitorFromDefault(RHDPtr rhdPtr) |
||
150 | { |
||
151 | struct rhdMonitor *Monitor; |
||
152 | DisplayModePtr Mode; |
||
153 | |||
154 | Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); |
||
155 | |||
156 | Monitor->Name = strdup("Default (SVGA)"); |
||
157 | Monitor->scrnIndex = rhdPtr->scrnIndex; |
||
158 | |||
159 | /* timing for pathetic 14" svga monitors */ |
||
160 | Monitor->numHSync = 3; |
||
161 | Monitor->HSync[0].lo = 31.5; |
||
162 | Monitor->HSync[0].hi = 31.5; |
||
163 | Monitor->HSync[1].lo = 35.15; |
||
164 | Monitor->HSync[1].hi = 35.15; |
||
165 | Monitor->HSync[2].lo = 35.5; |
||
166 | Monitor->HSync[2].hi = 35.5; |
||
167 | |||
168 | Monitor->numVRefresh = 1; |
||
169 | Monitor->VRefresh[0].lo = 50; |
||
170 | Monitor->VRefresh[0].hi = 61; |
||
171 | |||
172 | return Monitor; |
||
173 | } |
||
174 | |||
175 | /* |
||
176 | * This function tries to handle a configured monitor correctly. |
||
177 | * |
||
178 | * This either can be forced through the option, or is used when |
||
179 | * no monitors are autodetected. |
||
180 | */ |
||
181 | void |
||
182 | RHDConfigMonitorSet(RHDPtr rhdPtr, Bool UseConfig) |
||
183 | { |
||
184 | int i; |
||
185 | |||
186 | for (i = 0; i < RHD_CONNECTORS_MAX; i++) |
||
187 | if (rhdPtr->Connector[i] && rhdPtr->Connector[i]->Monitor) |
||
188 | break; |
||
189 | |||
190 | if (i == RHD_CONNECTORS_MAX) |
||
191 | xf86DrvMsg(scrnIndex, X_INFO, "No monitors autodetected; " |
||
192 | "attempting to work around this.\n"); |
||
193 | |||
194 | if (i == RHD_CONNECTORS_MAX) |
||
195 | { |
||
196 | rhdPtr->ConfigMonitor = rhdMonitorFromDefault(rhdPtr); |
||
197 | |||
198 | DBG(dbgprintf("Created monitor from default: \"%s\":\n", |
||
199 | rhdPtr->ConfigMonitor->Name)); |
||
200 | |||
201 | RHDMonitorPrint(rhdPtr->ConfigMonitor); |
||
202 | }; |
||
203 | } |
||
204 | |||
205 | /* |
||
206 | * Make sure that we keep only a single mode in our list. This mode should |
||
207 | * hopefully match our panel at native resolution correctly. |
||
208 | */ |
||
209 | static void |
||
210 | rhdPanelEDIDModesFilter(struct rhdMonitor *Monitor) |
||
211 | { |
||
212 | DisplayModeRec *Best = Monitor->Modes, *Mode, *Temp; |
||
213 | |||
214 | RHDFUNC(Monitor); |
||
215 | |||
216 | if (!Best || !Best->next) |
||
217 | return; /* don't bother */ |
||
218 | |||
219 | /* don't go for preferred, just take the biggest */ |
||
220 | for (Mode = Best->next; Mode; Mode = Mode->next) { |
||
221 | if (((Best->HDisplay <= Mode->HDisplay) && |
||
222 | (Best->VDisplay < Mode->VDisplay)) || |
||
223 | ((Best->HDisplay < Mode->HDisplay) && |
||
224 | (Best->VDisplay <= Mode->VDisplay))) |
||
225 | Best = Mode; |
||
226 | } |
||
227 | |||
228 | xf86DrvMsg(Monitor->scrnIndex, X_INFO, "Monitor \"%s\": Using Mode \"%s\"" |
||
229 | " for native resolution.\n", Monitor->Name, Best->name); |
||
230 | |||
231 | /* kill all other modes */ |
||
232 | Mode = Monitor->Modes; |
||
233 | while (Mode) { |
||
234 | Temp = Mode->next; |
||
235 | |||
236 | if (Mode != Best) { |
||
237 | RHDDebug(Monitor->scrnIndex, "Monitor \"%s\": Discarding Mode \"%s\"\n", |
||
238 | Monitor->Name, Mode->name); |
||
239 | |||
240 | xfree(Mode->name); |
||
241 | xfree(Mode); |
||
242 | } |
||
243 | Mode = Temp; |
||
244 | } |
||
245 | |||
246 | Best->next = NULL; |
||
247 | Best->prev = NULL; |
||
248 | Best->type |= M_T_PREFERRED; |
||
249 | Monitor->NativeMode = Best; |
||
250 | Monitor->Modes = Monitor->NativeMode; |
||
251 | Monitor->numHSync = 1; |
||
252 | Monitor->HSync[0].lo = Best->HSync; |
||
253 | Monitor->HSync[0].hi = Best->HSync; |
||
254 | Monitor->numVRefresh = 1; |
||
255 | Monitor->VRefresh[0].lo = Best->VRefresh; |
||
256 | Monitor->VRefresh[0].hi = Best->VRefresh; |
||
257 | Monitor->Bandwidth = Best->Clock; |
||
258 | } |
||
259 | |||
260 | /* |
||
261 | * |
||
262 | */ |
||
263 | void |
||
264 | rhdMonitorPrintEDID(struct rhdMonitor *Monitor, xf86MonPtr EDID) |
||
265 | { |
||
266 | xf86DrvMsg(EDID->scrnIndex, X_INFO, "EDID data for %s\n", |
||
267 | Monitor->Name); |
||
268 | xf86PrintEDID(EDID); |
||
269 | } |
||
270 | |||
271 | /* |
||
272 | * Panels are the most complicated case we need to handle here. |
||
273 | * Information can come from several places, and we need to make sure |
||
274 | * that we end up with only the native resolution in our table. |
||
275 | */ |
||
276 | static struct rhdMonitor * |
||
277 | rhdMonitorPanel(struct rhdConnector *Connector) |
||
278 | { |
||
279 | struct rhdMonitor *Monitor; |
||
280 | DisplayModeRec *Mode = NULL; |
||
281 | xf86MonPtr EDID = NULL; |
||
282 | |||
283 | RHDFUNC(Connector); |
||
284 | |||
285 | /* has priority over AtomBIOS EDID */ |
||
286 | if (Connector->DDC) |
||
287 | EDID = xf86DoEDID_DDC2(Connector->scrnIndex, Connector->DDC); |
||
288 | |||
289 | #ifdef ATOM_BIOS |
||
290 | { |
||
291 | RHDPtr rhdPtr = (RHDPtr)Connector->scrnIndex; |
||
292 | AtomBiosArgRec data; |
||
293 | AtomBiosResult Result; |
||
294 | |||
295 | Result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
296 | ATOMBIOS_GET_PANEL_MODE, &data); |
||
297 | if (Result == ATOM_SUCCESS) { |
||
298 | Mode = data.mode; |
||
299 | Mode->type |= M_T_PREFERRED; |
||
300 | } |
||
301 | if (!EDID) { |
||
302 | Result = RHDAtomBiosFunc(rhdPtr,rhdPtr->atomBIOS, |
||
303 | ATOMBIOS_GET_PANEL_EDID, &data); |
||
304 | if (Result == ATOM_SUCCESS) |
||
305 | EDID = xf86InterpretEDID(rhdPtr, data.EDIDBlock); |
||
306 | } |
||
307 | } |
||
308 | #endif |
||
309 | |||
310 | Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); |
||
311 | |||
312 | Monitor->scrnIndex = Connector->scrnIndex; |
||
313 | Monitor->EDID = EDID; |
||
314 | |||
315 | if (Mode) { |
||
316 | Monitor->Name = xstrdup("LVDS Panel"); |
||
317 | Monitor->Modes = RHDModesAdd(Monitor->Modes, Mode); |
||
318 | Monitor->NativeMode = Mode; |
||
319 | Monitor->numHSync = 1; |
||
320 | Monitor->HSync[0].lo = Mode->HSync; |
||
321 | Monitor->HSync[0].hi = Mode->HSync; |
||
322 | Monitor->numVRefresh = 1; |
||
323 | Monitor->VRefresh[0].lo = Mode->VRefresh; |
||
324 | Monitor->VRefresh[0].hi = Mode->VRefresh; |
||
325 | Monitor->Bandwidth = Mode->SynthClock; |
||
326 | |||
327 | /* Clueless atombios does give us a mode, but doesn't give us a |
||
328 | * DPI or a size. It is just perfect, right? */ |
||
329 | if (EDID) { |
||
330 | if (EDID->features.hsize) |
||
331 | Monitor->xDpi = (Mode->HDisplay * 2.54) / ((float) EDID->features.hsize) + 0.5; |
||
332 | if (EDID->features.vsize) |
||
333 | Monitor->yDpi = (Mode->VDisplay * 2.54) / ((float) EDID->features.vsize) + 0.5; |
||
334 | } |
||
335 | } else if (EDID) { |
||
336 | RHDMonitorEDIDSet(Monitor, EDID); |
||
337 | rhdPanelEDIDModesFilter(Monitor); |
||
338 | } else { |
||
339 | xf86DrvMsg(Connector->scrnIndex, X_ERROR, |
||
340 | "%s: No panel mode information found.\n", __func__); |
||
341 | xfree(Monitor); |
||
342 | return NULL; |
||
343 | } |
||
344 | |||
345 | /* panel should be driven at native resolution only. */ |
||
346 | Monitor->UseFixedModes = TRUE; |
||
347 | Monitor->ReducedAllowed = TRUE; |
||
348 | |||
349 | if (EDID) |
||
350 | rhdMonitorPrintEDID(Monitor, EDID); |
||
351 | |||
352 | return Monitor; |
||
353 | } |
||
354 | |||
355 | /* |
||
356 | * rhdMonitorTV(): get TV modes. Currently we can only get this from AtomBIOS. |
||
357 | */ |
||
358 | static struct rhdMonitor * |
||
359 | rhdMonitorTV(struct rhdConnector *Connector) |
||
360 | { |
||
361 | struct rhdMonitor *Monitor = NULL; |
||
362 | #ifdef ATOM_BIOS |
||
363 | RHDPtr rhdPtr = RHDPTRI(Connector); |
||
364 | DisplayModeRec *Mode = NULL; |
||
365 | AtomBiosArgRec arg; |
||
366 | |||
367 | RHDFUNC(Connector); |
||
368 | |||
369 | arg.tvMode = rhdPtr->tvMode; |
||
370 | if (RHDAtomBiosFunc(Connector->scrnIndex, rhdPtr->atomBIOS, |
||
371 | ATOM_ANALOG_TV_MODE, &arg) |
||
372 | != ATOM_SUCCESS) |
||
373 | return NULL; |
||
374 | |||
375 | Mode = arg.mode; |
||
376 | Mode->type |= M_T_PREFERRED; |
||
377 | |||
378 | Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); |
||
379 | |||
380 | Monitor->scrnIndex = Connector->scrnIndex; |
||
381 | Monitor->EDID = NULL; |
||
382 | |||
383 | Monitor->Name = xstrdup("TV"); |
||
384 | Monitor->Modes = RHDModesAdd(Monitor->Modes, Mode); |
||
385 | Monitor->NativeMode= Mode; |
||
386 | Monitor->numHSync = 1; |
||
387 | Monitor->HSync[0].lo = Mode->HSync; |
||
388 | Monitor->HSync[0].hi = Mode->HSync; |
||
389 | Monitor->numVRefresh = 1; |
||
390 | Monitor->VRefresh[0].lo = Mode->VRefresh; |
||
391 | Monitor->VRefresh[0].hi = Mode->VRefresh; |
||
392 | Monitor->Bandwidth = Mode->SynthClock; |
||
393 | |||
394 | /* TV should be driven at native resolution only. */ |
||
395 | Monitor->UseFixedModes = TRUE; |
||
396 | Monitor->ReducedAllowed = FALSE; |
||
397 | /* |
||
398 | * hack: the TV encoder takes care of that. |
||
399 | * The mode that goes in isn't what comes out. |
||
400 | */ |
||
401 | Mode->Flags &= ~(V_INTERLACE); |
||
402 | #endif |
||
403 | return Monitor; |
||
404 | } |
||
405 | |||
406 | /* |
||
407 | * |
||
408 | */ |
||
409 | struct rhdMonitor * |
||
410 | RHDMonitorInit(struct rhdConnector *Connector) |
||
411 | { |
||
412 | struct rhdMonitor *Monitor = NULL; |
||
413 | |||
414 | RHDFUNC(Connector); |
||
415 | |||
416 | if (Connector->Type == RHD_CONNECTOR_PANEL) |
||
417 | Monitor = rhdMonitorPanel(Connector); |
||
418 | else if (Connector->Type == RHD_CONNECTOR_TV) |
||
419 | Monitor = rhdMonitorTV(Connector); |
||
420 | else if (Connector->DDC) { |
||
421 | xf86MonPtr EDID = xf86DoEDID_DDC2(Connector->scrnIndex, Connector->DDC); |
||
422 | if (EDID) { |
||
423 | Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); |
||
424 | Monitor->scrnIndex = Connector->scrnIndex; |
||
425 | Monitor->EDID = EDID; |
||
426 | Monitor->NativeMode = NULL; |
||
427 | |||
428 | RHDMonitorEDIDSet(Monitor, EDID); |
||
429 | rhdMonitorPrintEDID(Monitor, EDID); |
||
430 | } |
||
431 | } |
||
432 | return Monitor; |
||
433 | } |
||
434 | |||
435 | /* |
||
436 | * |
||
437 | */ |
||
438 | void |
||
439 | RHDMonitorDestroy(struct rhdMonitor *Monitor) |
||
440 | { |
||
441 | DisplayModePtr Mode, Next; |
||
442 | |||
443 | for (Mode = Monitor->Modes; Mode;) { |
||
444 | Next = Mode->next; |
||
445 | |||
446 | xfree(Mode->name); |
||
447 | xfree(Mode); |
||
448 | |||
449 | Mode = Next; |
||
450 | } |
||
451 | |||
452 | if (Monitor->EDID) |
||
453 | xfree(Monitor->EDID->rawData); |
||
454 | xfree(Monitor->EDID); |
||
455 | xfree(Monitor->Name); |
||
456 | xfree(Monitor); |
||
457 | } |
||
458 | |||
459 | |||
460 | static unsigned char * VDIFRead(RHDPtr rhdPtr, I2CBusPtr pBus, int start); |
||
461 | |||
462 | #define RETRIES 4 |
||
463 | |||
464 | static xf86VdifLimitsPtr* get_limits(CARD8 *c); |
||
465 | static xf86VdifGammaPtr* get_gamma(CARD8 *c); |
||
466 | static xf86VdifTimingPtr* get_timings(CARD8 *c); |
||
467 | |||
468 | xf86vdifPtr xf86InterpretVdif(CARD8 *c) |
||
469 | { |
||
470 | xf86VdifPtr p = (xf86VdifPtr)c; |
||
471 | xf86vdifPtr vdif; |
||
472 | int i; |
||
473 | |||
474 | unsigned long l = 0; |
||
475 | |||
476 | if (c == NULL) return NULL; |
||
477 | if (p->VDIFId[0] != 'V' || p->VDIFId[1] != 'D' || p->VDIFId[2] != 'I' |
||
478 | || p->VDIFId[3] != 'F') return NULL; |
||
479 | for ( i = 12; i < p->FileLength; i++) |
||
480 | l += c[i]; |
||
481 | if ( l != p->Checksum) return NULL; |
||
482 | vdif = malloc(sizeof(xf86vdif)); |
||
483 | vdif->vdif = p; |
||
484 | vdif->limits = get_limits(c); |
||
485 | vdif->timings = get_timings(c); |
||
486 | vdif->gamma = get_gamma(c); |
||
487 | vdif->strings = VDIF_STRING(((xf86VdifPtr)c),0); |
||
488 | free(c); |
||
489 | return vdif; |
||
490 | } |
||
491 | |||
492 | static xf86VdifLimitsPtr* |
||
493 | get_limits(CARD8 *c) |
||
494 | { |
||
495 | int num, i, j; |
||
496 | xf86VdifLimitsPtr *pp; |
||
497 | xf86VdifLimitsPtr p; |
||
498 | |||
499 | num = ((xf86VdifPtr)c)->NumberOperationalLimits; |
||
500 | pp = malloc(sizeof(xf86VdifLimitsPtr) * (num+1)); |
||
501 | p = VDIF_OPERATIONAL_LIMITS(((xf86VdifPtr)c)); |
||
502 | j = 0; |
||
503 | for ( i = 0; i |
||
504 | if (p->Header.ScnTag == VDIF_OPERATIONAL_LIMITS_TAG) |
||
505 | pp[j++] = p; |
||
506 | VDIF_NEXT_OPERATIONAL_LIMITS(p); |
||
507 | } |
||
508 | pp[j] = NULL; |
||
509 | return pp; |
||
510 | } |
||
511 | |||
512 | static xf86VdifGammaPtr* |
||
513 | get_gamma(CARD8 *c) |
||
514 | { |
||
515 | int num, i, j; |
||
516 | xf86VdifGammaPtr *pp; |
||
517 | xf86VdifGammaPtr p; |
||
518 | |||
519 | num = ((xf86VdifPtr)c)->NumberOptions; |
||
520 | pp = malloc(sizeof(xf86VdifGammaPtr) * (num+1)); |
||
521 | p = (xf86VdifGammaPtr)VDIF_OPTIONS(((xf86VdifPtr)c)); |
||
522 | j = 0; |
||
523 | for ( i = 0; i |
||
524 | { |
||
525 | if (p->Header.ScnTag == VDIF_GAMMA_TABLE_TAG) |
||
526 | pp[j++] = p; |
||
527 | VDIF_NEXT_OPTIONS(p); |
||
528 | } |
||
529 | pp[j] = NULL; |
||
530 | return pp; |
||
531 | } |
||
532 | |||
533 | static xf86VdifTimingPtr* |
||
534 | get_timings(CARD8 *c) |
||
535 | { |
||
536 | int num, num_limits; |
||
537 | int i,j,k; |
||
538 | xf86VdifLimitsPtr lp; |
||
539 | xf86VdifTimingPtr *pp; |
||
540 | xf86VdifTimingPtr p; |
||
541 | |||
542 | num = ((xf86VdifPtr)c)->NumberOperationalLimits; |
||
543 | lp = VDIF_OPERATIONAL_LIMITS(((xf86VdifPtr)c)); |
||
544 | num_limits = 0; |
||
545 | for (i = 0; i < num; i++) { |
||
546 | if (lp->Header.ScnTag == VDIF_OPERATIONAL_LIMITS_TAG) |
||
547 | num_limits += lp->NumberPreadjustedTimings; |
||
548 | VDIF_NEXT_OPERATIONAL_LIMITS(lp); |
||
549 | } |
||
550 | pp = malloc(sizeof(xf86VdifTimingPtr) |
||
551 | * (num_limits+1)); |
||
552 | j = 0; |
||
553 | lp = VDIF_OPERATIONAL_LIMITS(((xf86VdifPtr) c)); |
||
554 | for (i = 0; i < num; i++) { |
||
555 | p = VDIF_PREADJUSTED_TIMING(lp); |
||
556 | for (k = 0; k < lp->NumberPreadjustedTimings; k++) { |
||
557 | if (p->Header.ScnTag == VDIF_PREADJUSTED_TIMING_TAG) |
||
558 | pp[j++] = p; |
||
559 | VDIF_NEXT_PREADJUSTED_TIMING(p); |
||
560 | } |
||
561 | VDIF_NEXT_OPERATIONAL_LIMITS(lp); |
||
562 | } |
||
563 | pp[j] = NULL; |
||
564 | return pp; |
||
565 | } |
||
566 | |||
567 | int DDC_checksum(unsigned char *block, int len) |
||
568 | { |
||
569 | int i, result = 0; |
||
570 | int not_null = 0; |
||
571 | |||
572 | for (i=0;i |
||
573 | { |
||
574 | not_null |= block[i]; |
||
575 | result += block[i]; |
||
576 | } |
||
577 | |||
578 | if (result & 0xFF) DBG(dbgprintf("DDC checksum not correct\n")); |
||
579 | if (!not_null) DBG(dbgprintf("DDC read all Null\n")); |
||
580 | |||
581 | /* catch the trivial case where all bytes are 0 */ |
||
582 | if (!not_null) return 1; |
||
583 | |||
584 | return (result&0xFF); |
||
585 | } |
||
586 | |||
587 | static unsigned char * |
||
588 | DDCRead_DDC2(RHDPtr rhdPtr, I2CBusPtr pBus, int start, int len) |
||
589 | { |
||
590 | I2CDevPtr dev; |
||
591 | unsigned char W_Buffer[2]; |
||
592 | int w_bytes; |
||
593 | unsigned char *R_Buffer; |
||
594 | int i; |
||
595 | |||
596 | RHDFUNC(rhdPtr); |
||
597 | |||
598 | // xf86LoaderReqSymLists(i2cSymbols, NULL); |
||
599 | |||
600 | if (!(dev = xf86I2CFindDev(pBus, 0x00A0))) |
||
601 | { |
||
602 | dev = xf86CreateI2CDevRec(); |
||
603 | dev->DevName = "ddc2"; |
||
604 | dev->SlaveAddr = 0xA0; |
||
605 | dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ |
||
606 | dev->StartTimeout = 550; |
||
607 | dev->BitTimeout = 40; |
||
608 | dev->ByteTimeout = 40; |
||
609 | dev->AcknTimeout = 40; |
||
610 | |||
611 | dev->pI2CBus = pBus; |
||
612 | if (!xf86I2CDevInit(dev)) |
||
613 | { |
||
614 | DBG(dbgprintf("No DDC2 device\n")); |
||
615 | return NULL; |
||
616 | } |
||
617 | } |
||
618 | if (start < 0x100) |
||
619 | { |
||
620 | w_bytes = 1; |
||
621 | W_Buffer[0] = start; |
||
622 | } |
||
623 | else |
||
624 | { |
||
625 | w_bytes = 2; |
||
626 | W_Buffer[0] = start & 0xFF; |
||
627 | W_Buffer[1] = (start & 0xFF00) >> 8; |
||
628 | } |
||
629 | |||
630 | R_Buffer = calloc(1,sizeof(unsigned char)* (len)); |
||
631 | |||
632 | if( !R_Buffer) |
||
633 | { |
||
634 | DBG(dbgprintf("R_Buffer = NULL\n")); |
||
635 | return NULL; |
||
636 | }; |
||
637 | |||
638 | for (i=0; i |
||
639 | { |
||
640 | if (xf86I2CWriteRead(dev, W_Buffer,w_bytes, R_Buffer,len)) |
||
641 | { |
||
642 | if (!DDC_checksum(R_Buffer,len)) |
||
643 | return R_Buffer; |
||
644 | else |
||
645 | DBG(dbgprintf("Checksum error in EDID block\n")); |
||
646 | } |
||
647 | else |
||
648 | DBG(dbgprintf("Error reading EDID block\n")); |
||
649 | } |
||
650 | xf86DestroyI2CDevRec(dev,TRUE); |
||
651 | free(R_Buffer); |
||
652 | return NULL; |
||
653 | } |
||
654 | |||
655 | static unsigned char* |
||
656 | EDID1Read_DDC2(RHDPtr rhdPtr, I2CBusPtr pBus) |
||
657 | { |
||
658 | return DDCRead_DDC2(rhdPtr, pBus, 0, EDID1_LEN); |
||
659 | } |
||
660 | |||
661 | xf86MonPtr |
||
662 | xf86DoEDID_DDC2(RHDPtr rhdPtr, I2CBusPtr pBus) |
||
663 | { |
||
664 | unsigned char *EDID_block = NULL; |
||
665 | unsigned char *VDIF_Block = NULL; |
||
666 | xf86MonPtr tmp = NULL; |
||
667 | |||
668 | RHDFUNC(rhdPtr); |
||
669 | |||
670 | EDID_block = EDID1Read_DDC2(rhdPtr,pBus); |
||
671 | |||
672 | if (EDID_block) |
||
673 | { |
||
674 | tmp = xf86InterpretEDID(rhdPtr,EDID_block); |
||
675 | } |
||
676 | else |
||
677 | { |
||
678 | DBG(dbgprintf("No EDID block returned\n")); |
||
679 | return NULL; |
||
680 | } |
||
681 | |||
682 | if (!tmp) |
||
683 | { |
||
684 | DBG(dbgprintf("Cannot interpret EDID block\n")); |
||
685 | return tmp; |
||
686 | } |
||
687 | DBG(dbgprintf("Sections to follow: %d\n",tmp->no_sections)); |
||
688 | |||
689 | VDIF_Block = |
||
690 | VDIFRead(rhdPtr, pBus, EDID1_LEN * (tmp->no_sections + 1)); |
||
691 | tmp->vdif = xf86InterpretVdif(VDIF_Block); |
||
692 | |||
693 | return tmp; |
||
694 | } |
||
695 | |||
696 | static unsigned char* |
||
697 | VDIFRead(RHDPtr rhdPtr, I2CBusPtr pBus, int start) |
||
698 | { |
||
699 | unsigned char * Buffer, *v_buffer = NULL, *v_bufferp = NULL; |
||
700 | int i, num = 0; |
||
701 | |||
702 | /* read VDIF length in 64 byte blocks */ |
||
703 | Buffer = DDCRead_DDC2(rhdPtr, pBus,start,64); |
||
704 | if (Buffer == NULL) |
||
705 | return NULL; |
||
706 | |||
707 | DBG(dbgprintf("number of 64 bit blocks: %i\n",Buffer[0])); |
||
708 | |||
709 | if ((num = Buffer[0]) > 0) |
||
710 | v_buffer = v_bufferp = malloc(sizeof(unsigned char) * 64 * num); |
||
711 | |||
712 | for (i = 0; i < num; i++) |
||
713 | { |
||
714 | Buffer = DDCRead_DDC2(rhdPtr, pBus,start,64); |
||
715 | if (Buffer == NULL) |
||
716 | { |
||
717 | free (v_buffer); |
||
718 | return NULL; |
||
719 | } |
||
720 | memcpy(v_bufferp,Buffer,63); /* 64th byte is checksum */ |
||
721 | free(Buffer); |
||
722 | v_bufferp += 63; |
||
723 | } |
||
724 | return v_buffer; |
||
725 | } |
||
726 | |||
727 | |||
728 | |||
729 | static void print_vendor(RHDPtr rhdPtr, struct vendor *); |
||
730 | static void print_version(RHDPtr rhdPtr, struct edid_version *); |
||
731 | static void print_display(RHDPtr rhdPtr, struct disp_features *, |
||
732 | struct edid_version *); |
||
733 | static void print_established_timings(RHDPtr rhdPtr, |
||
734 | struct established_timings *); |
||
735 | static void print_std_timings(RHDPtr rhdPtr, struct std_timings *); |
||
736 | static void print_detailed_monitor_section(RHDPtr rhdPtr, |
||
737 | struct detailed_monitor_section *); |
||
738 | static void print_detailed_timings(RHDPtr rhdPtr, struct detailed_timings *); |
||
739 | |||
740 | static void print_input_features(RHDPtr rhdPtr, struct disp_features *); |
||
741 | static void print_dpms_features(RHDPtr rhdPtr, struct disp_features *, |
||
742 | struct edid_version *v); |
||
743 | static void print_whitepoint(RHDPtr rhdPtr, struct disp_features *); |
||
744 | static void print_number_sections(RHDPtr rhdPtr, int); |
||
745 | |||
746 | xf86MonPtr |
||
747 | xf86PrintEDID(xf86MonPtr m) |
||
748 | { |
||
749 | if (!(m)) return NULL; |
||
750 | print_vendor(m->rhdPtr,&m->vendor); |
||
751 | print_version(m->rhdPtr,&m->ver); |
||
752 | print_display(m->rhdPtr,&m->features, &m->ver); |
||
753 | print_established_timings(m->rhdPtr,&m->timings1); |
||
754 | print_std_timings(m->rhdPtr,m->timings2); |
||
755 | print_detailed_monitor_section(m->rhdPtr,m->det_mon); |
||
756 | print_number_sections(m->rhdPtr,m->no_sections); |
||
757 | |||
758 | return m; |
||
759 | } |
||
760 | |||
761 | static void |
||
762 | print_vendor(RHDPtr rhdPtr, struct vendor *c) |
||
763 | { |
||
764 | DBG(dbgprintf("Manufacturer: %s Model: %x Serial#: %u\n", |
||
765 | (char *)&c->name, c->prod_id, c->serial)); |
||
766 | DBG(dbgprintf("Year: %u Week: %u\n", c->year, c->week)); |
||
767 | } |
||
768 | |||
769 | static void |
||
770 | print_version(RHDPtr rhdPtr, struct edid_version *c) |
||
771 | { |
||
772 | DBG(dbgprintf("EDID Version: %u.%u\n",c->version,c->revision)); |
||
773 | } |
||
774 | |||
775 | static void |
||
776 | print_display(RHDPtr rhdPtr, struct disp_features *disp, |
||
777 | struct edid_version *version) |
||
778 | { |
||
779 | print_input_features(rhdPtr,disp); |
||
780 | DBG(dbgprintf("Max H-Image Size [cm]: ")); |
||
781 | if (disp->hsize) |
||
782 | DBG(dbgprintf("horiz.: %i ",disp->hsize)); |
||
783 | else |
||
784 | DBG(dbgprintf("H-Size may change, ")); |
||
785 | if (disp->vsize) |
||
786 | DBG(dbgprintf("vert.: %i\n",disp->vsize)); |
||
787 | else |
||
788 | DBG(dbgprintf("V-Size may change\n")); |
||
789 | DBG(dbgprintf("Gamma: %.2f\n", (double)disp->gamma)); |
||
790 | print_dpms_features(rhdPtr,disp,version); |
||
791 | print_whitepoint(rhdPtr,disp); |
||
792 | } |
||
793 | |||
794 | static void |
||
795 | print_input_features(RHDPtr rhdPtr, struct disp_features *c) |
||
796 | { |
||
797 | if (DIGITAL(c->input_type)) |
||
798 | { |
||
799 | DBG(dbgprintf("Digital Display Input\n")); |
||
800 | if (DFP1(c->input_dfp)) |
||
801 | DBG(dbgprintf("DFP 1.x compatible TMDS\n")); |
||
802 | } |
||
803 | else |
||
804 | { |
||
805 | DBG(dbgprintf("Analog Display Input, ")); |
||
806 | DBG(dbgprintf("Input Voltage Level: ")); |
||
807 | switch (c->input_voltage) |
||
808 | { |
||
809 | case V070: |
||
810 | DBG(dbgprintf("0.700/0.300 V\n")); |
||
811 | break; |
||
812 | case V071: |
||
813 | DBG(dbgprintf("0.714/0.286 V\n")); |
||
814 | break; |
||
815 | case V100: |
||
816 | DBG(dbgprintf("1.000/0.400 V\n")); |
||
817 | break; |
||
818 | case V007: |
||
819 | DBG(dbgprintf("0.700/0.700 V\n")); |
||
820 | break; |
||
821 | default: |
||
822 | DBG(dbgprintf("undefined\n")); |
||
823 | } |
||
824 | if (SIG_SETUP(c->input_setup)) |
||
825 | DBG(dbgprintf("Signal levels configurable\n")); |
||
826 | DBG(dbgprintf("Sync:")); |
||
827 | if (SEP_SYNC(c->input_sync)) |
||
828 | DBG(dbgprintf(" Separate")); |
||
829 | if (COMP_SYNC(c->input_sync)) |
||
830 | DBG(dbgprintf(" Composite")); |
||
831 | if (SYNC_O_GREEN(c->input_sync)) |
||
832 | DBG(dbgprintf(" SyncOnGreen")); |
||
833 | if (SYNC_SERR(c->input_sync)) |
||
834 | DBG(dbgprintf("Serration on. " |
||
835 | "V.Sync Pulse req. if CompSync or SyncOnGreen\n")); |
||
836 | else |
||
837 | DBG(dbgprintf("\n")); |
||
838 | } |
||
839 | } |
||
840 | |||
841 | static void |
||
842 | print_dpms_features(RHDPtr rhdPtr, struct disp_features *c, |
||
843 | struct edid_version *v) |
||
844 | { |
||
845 | if (c->dpms) |
||
846 | { |
||
847 | DBG(dbgprintf("DPMS capabilities:")); |
||
848 | if (DPMS_STANDBY(c->dpms)) |
||
849 | DBG(dbgprintf(" StandBy")); |
||
850 | if (DPMS_SUSPEND(c->dpms)) |
||
851 | DBG(dbgprintf(" Suspend")); |
||
852 | if (DPMS_OFF(c->dpms)) |
||
853 | DBG(dbgprintf(" Off")); |
||
854 | } |
||
855 | else |
||
856 | DBG(dbgprintf("No DPMS capabilities specified")); |
||
857 | switch (c->display_type) |
||
858 | { |
||
859 | case DISP_MONO: |
||
860 | DBG(dbgprintf("; Monochorome/GrayScale Display\n")); |
||
861 | break; |
||
862 | case DISP_RGB: |
||
863 | DBG(dbgprintf("; RGB/Color Display\n")); |
||
864 | break; |
||
865 | case DISP_MULTCOLOR: |
||
866 | DBG(dbgprintf("; Non RGB Multicolor Display\n")); |
||
867 | break; |
||
868 | default: |
||
869 | DBG(dbgprintf("\n")); |
||
870 | break; |
||
871 | } |
||
872 | if (STD_COLOR_SPACE(c->msc)) |
||
873 | DBG(dbgprintf("Default color space is primary color space\n")); |
||
874 | if (PREFERRED_TIMING_MODE(c->msc)) |
||
875 | DBG(dbgprintf("First detailed timing is preferred mode\n")); |
||
876 | else |
||
877 | if (v->version == 1 && v->revision >= 3) |
||
878 | DBG(dbgprintf("First detailed timing not preferred " |
||
879 | "mode in violation of standard!")); |
||
880 | if (GFT_SUPPORTED(c->msc)) |
||
881 | DBG(dbgprintf("GTF timings supported\n")); |
||
882 | } |
||
883 | |||
884 | static void |
||
885 | print_whitepoint(RHDPtr rhdPtr, struct disp_features *disp) |
||
886 | { |
||
887 | DBG(dbgprintf("redX: %.3f redY: %.3f ", |
||
888 | (double)disp->redx,(double)disp->redy)); |
||
889 | DBG(dbgprintf("greenX: %.3f greenY: %.3f\n", |
||
890 | (double)disp->greenx,(double)disp->greeny)); |
||
891 | DBG(dbgprintf("blueX: %.3f blueY: %.3f ", |
||
892 | (double)disp->bluex,(double)disp->bluey)); |
||
893 | DBG(dbgprintf("whiteX: %.3f whiteY: %.3f\n", |
||
894 | (double)disp->whitex,(double)disp->whitey)); |
||
895 | } |
||
896 | |||
897 | static void |
||
898 | print_established_timings(RHDPtr rhdPtr, struct established_timings *t) |
||
899 | { |
||
900 | unsigned char c; |
||
901 | |||
902 | if (t->t1 || t->t2 || t->t_manu) |
||
903 | DBG(dbgprintf("Supported VESA Video Modes:\n")); |
||
904 | c=t->t1; |
||
905 | if (c&0x80) DBG(dbgprintf("720x400@70Hz\n")); |
||
906 | if (c&0x40) DBG(dbgprintf("720x400@88Hz\n")); |
||
907 | if (c&0x20) DBG(dbgprintf("640x480@60Hz\n")); |
||
908 | if (c&0x10) DBG(dbgprintf("640x480@67Hz\n")); |
||
909 | if (c&0x08) DBG(dbgprintf("640x480@72Hz\n")); |
||
910 | if (c&0x04) DBG(dbgprintf("640x480@75Hz\n")); |
||
911 | if (c&0x02) DBG(dbgprintf("800x600@56Hz\n")); |
||
912 | if (c&0x01) DBG(dbgprintf("800x600@60Hz\n")); |
||
913 | c=t->t2; |
||
914 | if (c&0x80) DBG(dbgprintf("800x600@72Hz\n")); |
||
915 | if (c&0x40) DBG(dbgprintf("800x600@75Hz\n")); |
||
916 | if (c&0x20) DBG(dbgprintf("832x624@75Hz\n")); |
||
917 | if (c&0x10) DBG(dbgprintf("1024x768@87Hz (interlaced)\n")); |
||
918 | if (c&0x08) DBG(dbgprintf("1024x768@60Hz\n")); |
||
919 | if (c&0x04) DBG(dbgprintf("1024x768@70Hz\n")); |
||
920 | if (c&0x02) DBG(dbgprintf("1024x768@75Hz\n")); |
||
921 | if (c&0x01) DBG(dbgprintf("1280x1024@75Hz\n")); |
||
922 | c=t->t_manu; |
||
923 | if (c&0x80) DBG(dbgprintf("1152x870@75Hz\n")); |
||
924 | DBG(dbgprintf("Manufacturer's mask: %X\n",c&0x7F)); |
||
925 | } |
||
926 | |||
927 | static void |
||
928 | print_std_timings(RHDPtr rhdPtr, struct std_timings *t) |
||
929 | { |
||
930 | int i; |
||
931 | char done = 0; |
||
932 | for (i=0;i |
||
933 | { |
||
934 | if (t[i].hsize > 256) /* sanity check */ |
||
935 | { |
||
936 | if (!done) |
||
937 | { |
||
938 | DBG(dbgprintf("Supported Future Video Modes:\n")); |
||
939 | done = 1; |
||
940 | } |
||
941 | DBG(dbgprintf("#%d: hsize: %i vsize %i refresh: %i vid: %i\n", |
||
942 | i, t[i].hsize, t[i].vsize, t[i].refresh, t[i].id)); |
||
943 | } |
||
944 | } |
||
945 | } |
||
946 | |||
947 | static void |
||
948 | print_detailed_monitor_section(RHDPtr rhdPtr, |
||
949 | struct detailed_monitor_section *m) |
||
950 | { |
||
951 | int i,j; |
||
952 | |||
953 | for (i=0;i |
||
954 | { |
||
955 | switch (m[i].type) |
||
956 | { |
||
957 | case DT: |
||
958 | print_detailed_timings(rhdPtr,&m[i].section.d_timings); |
||
959 | break; |
||
960 | case DS_SERIAL: |
||
961 | DBG(dbgprintf("Serial No: %s\n",m[i].section.serial)); |
||
962 | break; |
||
963 | case DS_ASCII_STR: |
||
964 | DBG(dbgprintf(" %s\n",m[i].section.ascii_data)); |
||
965 | break; |
||
966 | case DS_NAME: |
||
967 | DBG(dbgprintf("Monitor name: %s\n",m[i].section.name)); |
||
968 | break; |
||
969 | case DS_RANGES: |
||
970 | DBG(dbgprintf("Ranges: V min: %i V max: %i Hz, H min: %i H max: %i kHz,", |
||
971 | m[i].section.ranges.min_v, m[i].section.ranges.max_v, |
||
972 | m[i].section.ranges.min_h, m[i].section.ranges.max_h)); |
||
973 | if (m[i].section.ranges.max_clock != 0) |
||
974 | DBG(dbgprintf(" PixClock max %i MHz\n",m[i].section.ranges.max_clock)); |
||
975 | else |
||
976 | DBG(dbgprintf("\n")); |
||
977 | if (m[i].section.ranges.gtf_2nd_f > 0) |
||
978 | DBG(dbgprintf(" 2nd GTF parameters: f: %i kHz " |
||
979 | "c: %i m: %i k %i j %i\n", |
||
980 | m[i].section.ranges.gtf_2nd_f, |
||
981 | m[i].section.ranges.gtf_2nd_c, |
||
982 | m[i].section.ranges.gtf_2nd_m, |
||
983 | m[i].section.ranges.gtf_2nd_k, |
||
984 | m[i].section.ranges.gtf_2nd_j)); |
||
985 | break; |
||
986 | case DS_STD_TIMINGS: |
||
987 | for (j = 0; j<5; j++) |
||
988 | DBG(dbgprintf("#%i: hsize: %i vsize %i refresh: %i " |
||
989 | "vid: %i\n",i,m[i].section.std_t[i].hsize, |
||
990 | m[i].section.std_t[j].vsize,m[i].section.std_t[j].refresh, |
||
991 | m[i].section.std_t[j].id)); |
||
992 | break; |
||
993 | case DS_WHITE_P: |
||
994 | for (j = 0; j<2; j++) |
||
995 | if (m[i].section.wp[j].index != 0) |
||
996 | DBG(dbgprintf("White point %i: whiteX: %f, whiteY: %f; gamma: %f\n", |
||
997 | m[i].section.wp[j].index,(double)m[i].section.wp[j].white_x, |
||
998 | (double)m[i].section.wp[j].white_y, |
||
999 | (double)m[i].section.wp[j].white_gamma)); |
||
1000 | break; |
||
1001 | case DS_DUMMY: |
||
1002 | default: |
||
1003 | break; |
||
1004 | } |
||
1005 | } |
||
1006 | } |
||
1007 | |||
1008 | static void |
||
1009 | print_detailed_timings(RHDPtr rhdPtr, struct detailed_timings *t) |
||
1010 | { |
||
1011 | |||
1012 | if (t->clock > 15000000) /* sanity check */ |
||
1013 | { |
||
1014 | DBG(dbgprintf("Supported additional Video Mode:\n")); |
||
1015 | DBG(dbgprintf("clock: %.1f MHz ",(double)t->clock/1000000.0)); |
||
1016 | DBG(dbgprintf("Image Size: %i x %i mm\n",t->h_size,t->v_size)); |
||
1017 | DBG(dbgprintf("h_active: %i h_sync: %i h_sync_end %i h_blank_end %i ", |
||
1018 | t->h_active, t->h_sync_off + t->h_active, |
||
1019 | t->h_sync_off + t->h_sync_width + t->h_active, |
||
1020 | t->h_active + t->h_blanking)); |
||
1021 | DBG(dbgprintf("h_border: %i\n",t->h_border)); |
||
1022 | DBG(dbgprintf("v_active: %i v_sync: %i v_sync_end %i v_blanking: %i ", |
||
1023 | t->v_active, t->v_sync_off + t->v_active, |
||
1024 | t->v_sync_off + t->v_sync_width + t->v_active, |
||
1025 | t->v_active + t->v_blanking)); |
||
1026 | DBG(dbgprintf("v_border: %i\n",t->v_border)); |
||
1027 | if (IS_STEREO(t->stereo)) |
||
1028 | { |
||
1029 | DBG(dbgprintf("Stereo: ")); |
||
1030 | if (IS_RIGHT_STEREO(t->stereo)) |
||
1031 | { |
||
1032 | if (!t->stereo_1) |
||
1033 | DBG(dbgprintf("right channel on sync\n")); |
||
1034 | else |
||
1035 | DBG(dbgprintf("left channel on sync\n")); |
||
1036 | } |
||
1037 | else |
||
1038 | if (IS_LEFT_STEREO(t->stereo)) |
||
1039 | { |
||
1040 | if (!t->stereo_1) |
||
1041 | DBG(dbgprintf("right channel on even line\n")); |
||
1042 | else |
||
1043 | DBG(dbgprintf("left channel on evel line\n")); |
||
1044 | } |
||
1045 | if (IS_4WAY_STEREO(t->stereo)) |
||
1046 | { |
||
1047 | if (!t->stereo_1) |
||
1048 | DBG(dbgprintf("4-way interleaved\n")); |
||
1049 | else |
||
1050 | DBG(dbgprintf("side-by-side interleaved")); |
||
1051 | } |
||
1052 | } |
||
1053 | } |
||
1054 | } |
||
1055 | |||
1056 | static void |
||
1057 | print_number_sections(RHDPtr rhdPtr, int num) |
||
1058 | { |
||
1059 | if (num) |
||
1060 | DBG(dbgprintf("Number of EDID sections to follow: %i\n",num)); |
||
1061 | } |
||
1062 | |||
1063 | |||
1064 | |||
1065 | static void get_vendor_section(Uchar*, struct vendor *); |
||
1066 | static void get_version_section(Uchar*, struct edid_version *); |
||
1067 | static void get_display_section(Uchar*, struct disp_features *, |
||
1068 | struct edid_version *); |
||
1069 | static void get_established_timing_section(Uchar*, struct established_timings *); |
||
1070 | static void get_std_timing_section(Uchar*, struct std_timings *, |
||
1071 | struct edid_version *); |
||
1072 | static void get_dt_md_section(Uchar *, struct edid_version *, |
||
1073 | struct detailed_monitor_section *det_mon); |
||
1074 | static void copy_string(Uchar *, Uchar *); |
||
1075 | static void get_dst_timing_section(Uchar *, struct std_timings *, |
||
1076 | struct edid_version *); |
||
1077 | static void get_monitor_ranges(Uchar *, struct monitor_ranges *); |
||
1078 | static void get_whitepoint_section(Uchar *, struct whitePoints *); |
||
1079 | static void get_detailed_timing_section(Uchar*, struct detailed_timings *); |
||
1080 | static Bool validate_version(RHDPtr rhdPtr, struct edid_version *); |
||
1081 | |||
1082 | |||
1083 | xf86MonPtr |
||
1084 | xf86InterpretEDID(int scrnIndex, Uchar *block) |
||
1085 | { |
||
1086 | xf86MonPtr m; |
||
1087 | RHDPtr rhdPtr = (RHDPtr)scrnIndex; |
||
1088 | |||
1089 | if (!block) return NULL; |
||
1090 | if (! (m = calloc(sizeof(xf86Monitor),1))) return NULL; |
||
1091 | m->rhdPtr = rhdPtr; |
||
1092 | m->rawData = block; |
||
1093 | |||
1094 | get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor); |
||
1095 | get_version_section(SECTION(VERSION_SECTION,block),&m->ver); |
||
1096 | if (!validate_version(rhdPtr, &m->ver)) goto error; |
||
1097 | get_display_section(SECTION(DISPLAY_SECTION,block),&m->features, |
||
1098 | &m->ver); |
||
1099 | get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block), |
||
1100 | &m->timings1); |
||
1101 | get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2, |
||
1102 | &m->ver); |
||
1103 | get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon); |
||
1104 | m->no_sections = (int)*(char *)SECTION(NO_EDID,block); |
||
1105 | |||
1106 | return (m); |
||
1107 | |||
1108 | error: |
||
1109 | free(m); |
||
1110 | return NULL; |
||
1111 | } |
||
1112 | |||
1113 | static void |
||
1114 | get_vendor_section(Uchar *c, struct vendor *r) |
||
1115 | { |
||
1116 | r->name[0] = L1; |
||
1117 | r->name[1] = L2; |
||
1118 | r->name[2] = L3; |
||
1119 | r->name[3] = '\0'; |
||
1120 | |||
1121 | r->prod_id = PROD_ID; |
||
1122 | r->serial = SERIAL_NO; |
||
1123 | r->week = WEEK; |
||
1124 | r->year = YEAR; |
||
1125 | } |
||
1126 | |||
1127 | static void |
||
1128 | get_version_section(Uchar *c, struct edid_version *r) |
||
1129 | { |
||
1130 | r->version = VERSION; |
||
1131 | r->revision = REVISION; |
||
1132 | } |
||
1133 | |||
1134 | static void |
||
1135 | get_display_section(Uchar *c, struct disp_features *r, |
||
1136 | struct edid_version *v) |
||
1137 | { |
||
1138 | r->input_type = INPUT_TYPE; |
||
1139 | if (!DIGITAL(r->input_type)) |
||
1140 | { |
||
1141 | r->input_voltage = INPUT_VOLTAGE; |
||
1142 | r->input_setup = SETUP; |
||
1143 | r->input_sync = SYNC; |
||
1144 | } |
||
1145 | else |
||
1146 | if (v->version > 1 || v->revision > 2) |
||
1147 | r->input_dfp = DFP; |
||
1148 | r->hsize = HSIZE_MAX; |
||
1149 | r->vsize = VSIZE_MAX; |
||
1150 | r->gamma = GAMMA; |
||
1151 | r->dpms = DPMS; |
||
1152 | r->display_type = DISPLAY_TYPE; |
||
1153 | r->msc = MSC; |
||
1154 | r->redx = REDX; |
||
1155 | r->redy = REDY; |
||
1156 | r->greenx = GREENX; |
||
1157 | r->greeny = GREENY; |
||
1158 | r->bluex = BLUEX; |
||
1159 | r->bluey = BLUEY; |
||
1160 | r->whitex = WHITEX; |
||
1161 | r->whitey = WHITEY; |
||
1162 | } |
||
1163 | |||
1164 | static void |
||
1165 | get_established_timing_section(Uchar *c, struct established_timings *r) |
||
1166 | { |
||
1167 | r->t1 = T1; |
||
1168 | r->t2 = T2; |
||
1169 | r->t_manu = T_MANU; |
||
1170 | } |
||
1171 | |||
1172 | static void |
||
1173 | get_std_timing_section(Uchar *c, struct std_timings *r, |
||
1174 | struct edid_version *v) |
||
1175 | { |
||
1176 | int i; |
||
1177 | |||
1178 | for (i=0;i |
||
1179 | { |
||
1180 | if (VALID_TIMING) |
||
1181 | { |
||
1182 | r[i].hsize = HSIZE1; |
||
1183 | VSIZE1(r[i].vsize); |
||
1184 | r[i].refresh = REFRESH_R; |
||
1185 | r[i].id = STD_TIMING_ID; |
||
1186 | } |
||
1187 | else |
||
1188 | { |
||
1189 | r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0; |
||
1190 | } |
||
1191 | NEXT_STD_TIMING; |
||
1192 | } |
||
1193 | } |
||
1194 | |||
1195 | static void |
||
1196 | get_dt_md_section(Uchar *c, struct edid_version *ver, |
||
1197 | struct detailed_monitor_section *det_mon) |
||
1198 | { |
||
1199 | int i; |
||
1200 | |||
1201 | for (i=0;i |
||
1202 | if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) { |
||
1203 | |||
1204 | switch (MONITOR_DESC_TYPE) { |
||
1205 | case SERIAL_NUMBER: |
||
1206 | det_mon[i].type = DS_SERIAL; |
||
1207 | copy_string(c,det_mon[i].section.serial); |
||
1208 | break; |
||
1209 | case ASCII_STR: |
||
1210 | det_mon[i].type = DS_ASCII_STR; |
||
1211 | copy_string(c,det_mon[i].section.ascii_data); |
||
1212 | break; |
||
1213 | case MONITOR_RANGES: |
||
1214 | det_mon[i].type = DS_RANGES; |
||
1215 | get_monitor_ranges(c,&det_mon[i].section.ranges); |
||
1216 | break; |
||
1217 | case MONITOR_NAME: |
||
1218 | det_mon[i].type = DS_NAME; |
||
1219 | copy_string(c,det_mon[i].section.name); |
||
1220 | break; |
||
1221 | case ADD_COLOR_POINT: |
||
1222 | det_mon[i].type = DS_WHITE_P; |
||
1223 | get_whitepoint_section(c,det_mon[i].section.wp); |
||
1224 | break; |
||
1225 | case ADD_STD_TIMINGS: |
||
1226 | det_mon[i].type = DS_STD_TIMINGS; |
||
1227 | get_dst_timing_section(c,det_mon[i].section.std_t, ver); |
||
1228 | break; |
||
1229 | case ADD_DUMMY: |
||
1230 | det_mon[i].type = DS_DUMMY; |
||
1231 | break; |
||
1232 | } |
||
1233 | } else { |
||
1234 | det_mon[i].type = DT; |
||
1235 | get_detailed_timing_section(c,&det_mon[i].section.d_timings); |
||
1236 | } |
||
1237 | NEXT_DT_MD_SECTION; |
||
1238 | } |
||
1239 | } |
||
1240 | |||
1241 | static void |
||
1242 | copy_string(Uchar *c, Uchar *s) |
||
1243 | { |
||
1244 | int i; |
||
1245 | c = c + 5; |
||
1246 | for (i = 0; (i < 13 && *c != 0x0A); i++) |
||
1247 | *(s++) = *(c++); |
||
1248 | *s = 0; |
||
1249 | while (i-- && (*--s == 0x20)) *s = 0; |
||
1250 | } |
||
1251 | |||
1252 | static void |
||
1253 | get_dst_timing_section(Uchar *c, struct std_timings *t, |
||
1254 | struct edid_version *v) |
||
1255 | { |
||
1256 | int j; |
||
1257 | c = c + 5; |
||
1258 | for (j = 0; j < 5; j++) { |
||
1259 | t[j].hsize = HSIZE1; |
||
1260 | VSIZE1(t[j].vsize); |
||
1261 | t[j].refresh = REFRESH_R; |
||
1262 | t[j].id = STD_TIMING_ID; |
||
1263 | NEXT_STD_TIMING; |
||
1264 | } |
||
1265 | } |
||
1266 | |||
1267 | static void |
||
1268 | get_monitor_ranges(Uchar *c, struct monitor_ranges *r) |
||
1269 | { |
||
1270 | r->min_v = MIN_V; |
||
1271 | r->max_v = MAX_V; |
||
1272 | r->min_h = MIN_H; |
||
1273 | r->max_h = MAX_H; |
||
1274 | r->max_clock = 0; |
||
1275 | if(MAX_CLOCK != 0xff) /* is specified? */ |
||
1276 | r->max_clock = MAX_CLOCK * 10; |
||
1277 | if (HAVE_2ND_GTF) { |
||
1278 | r->gtf_2nd_f = F_2ND_GTF; |
||
1279 | r->gtf_2nd_c = C_2ND_GTF; |
||
1280 | r->gtf_2nd_m = M_2ND_GTF; |
||
1281 | r->gtf_2nd_k = K_2ND_GTF; |
||
1282 | r->gtf_2nd_j = J_2ND_GTF; |
||
1283 | } else |
||
1284 | r->gtf_2nd_f = 0; |
||
1285 | } |
||
1286 | |||
1287 | static void |
||
1288 | get_whitepoint_section(Uchar *c, struct whitePoints *wp) |
||
1289 | { |
||
1290 | wp[1].white_x = WHITEX1; |
||
1291 | wp[1].white_y = WHITEY1; |
||
1292 | wp[2].white_x = WHITEX2; |
||
1293 | wp[2].white_y = WHITEY2; |
||
1294 | wp[1].index = WHITE_INDEX1; |
||
1295 | wp[2].index = WHITE_INDEX2; |
||
1296 | wp[1].white_gamma = WHITE_GAMMA1; |
||
1297 | wp[2].white_gamma = WHITE_GAMMA2; |
||
1298 | } |
||
1299 | |||
1300 | static void |
||
1301 | get_detailed_timing_section(Uchar *c, struct detailed_timings *r) |
||
1302 | { |
||
1303 | r->clock = PIXEL_CLOCK; |
||
1304 | r->h_active = H_ACTIVE; |
||
1305 | r->h_blanking = H_BLANK; |
||
1306 | r->v_active = V_ACTIVE; |
||
1307 | r->v_blanking = V_BLANK; |
||
1308 | r->h_sync_off = H_SYNC_OFF; |
||
1309 | r->h_sync_width = H_SYNC_WIDTH; |
||
1310 | r->v_sync_off = V_SYNC_OFF; |
||
1311 | r->v_sync_width = V_SYNC_WIDTH; |
||
1312 | r->h_size = H_SIZE; |
||
1313 | r->v_size = V_SIZE; |
||
1314 | r->h_border = H_BORDER; |
||
1315 | r->v_border = V_BORDER; |
||
1316 | r->interlaced = INTERLACED; |
||
1317 | r->stereo = STEREO; |
||
1318 | r->stereo_1 = STEREO1; |
||
1319 | r->sync = SYNC_T; |
||
1320 | r->misc = MISC; |
||
1321 | } |
||
1322 | |||
1323 | |||
1324 | static Bool |
||
1325 | validate_version(RHDPtr rhdPtr, struct edid_version *r) |
||
1326 | { |
||
1327 | if (r->version != 1) |
||
1328 | return FALSE; |
||
1329 | if (r->revision > 3) |
||
1330 | { |
||
1331 | DBG(dbgprintf("EDID Version 1.%d not yet supported\n",r->revision)); |
||
1332 | return FALSE; |
||
1333 | } |
||
1334 | return TRUE; |
||
1335 | }>> |