Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/modules/Resolution/edid.c

1/*
2 * edid.c
3 *
4 *
5 * Created by Evan Lojewski on 12/1/09.
6 * Copyright 2009. All rights reserved.
7 *
8 *Slice 2010, based on Joblo works
9 */
10
11
12//#include "libsaio.h"
13#include "edid.h"
14#include "vbe.h"
15#include "graphics.h"
16#include "boot.h"
17//----------------------------------------------------------------------------------
18
19#define FBMON_FIX_HEADER 1
20#define FBMON_FIX_INPUT 2
21#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
22
23//----------------------------------------------------------------------------------
24/*
25struct broken_edid {
26const char manufacturer[4];
27UInt32 model;
28UInt32 fix;
29};
30
31//----------------------------------------------------------------------------------
32
33broken_edid brokendb[] = {
34// DEC FR-PCXAV-YZ *
35{ "DEC", 0x073a, FBMON_FIX_HEADER,},
36// ViewSonic PF775a *
37{ "VSC", 0x5a44, FBMON_FIX_INPUT,}
38};
39//----------------------------------------------------------------------------------
40*/
41const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
42
43//----------------------------------------------------------------------------------
44int edid_compare(unsigned char *edid1, unsigned char *edid2)
45{
46int result = 0;
47unsigned char *block = edid1 + ID_MANUFACTURER_NAME, manufacturer1[4], manufacturer2[4];;
48manufacturer1[0] = ((block[0] & 0x7c) >> 2) + '@';
49manufacturer1[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';
50manufacturer1[2] = (block[1] & 0x1f) + '@';
51manufacturer1[3] = 0;
52
53block = edid2 + ID_MANUFACTURER_NAME;
54manufacturer2[0] = ((block[0] & 0x7c) >> 2) + '@';
55manufacturer2[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';
56manufacturer2[2] = (block[1] & 0x1f) + '@';
57manufacturer2[3] = 0;
58int x;
59for(x = 0; x < 4; x++)
60{
61if(manufacturer1[x] == manufacturer2[x])
62result++;
63}
64
65return result;
66}
67
68int check_edid(unsigned char *edid)
69{
70unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
71//unsigned char *b;
72UInt32 model;
73//int i, fix = 0, ret = 0;
74
75manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
76manufacturer[1] = ((block[0] & 0x03) << 3) +
77((block[1] & 0xe0) >> 5) + '@';
78manufacturer[2] = (block[1] & 0x1f) + '@';
79manufacturer[3] = 0;
80model = block[2] + (block[3] << 8);
81/*
82for (i = 0; i < (int)ARRAY_SIZE(brokendb); i++) {
83if (!strncmp((const char *)manufacturer, brokendb[i].manufacturer, 4) &&
84brokendb[i].model == model) {
85DEBG("ATIFB: The EDID Block of "
86 "Manufacturer: %s Model: 0x%08lx is known to "
87 "be broken,\n", manufacturer, model);
88fix = brokendb[i].fix;
89break;
90}
91}
92
93switch (fix) {
94case FBMON_FIX_HEADER:
95for (i = 0; i < 8; i++) {
96if (edid[i] != edid_v1_header[i])
97ret = fix;
98}
99break;
100case FBMON_FIX_INPUT:
101b = edid + EDID_STRUCT_DISPLAY;
102/// Only if display is GTF capable will
103 //the input type be reset to analog *
104if (b[4] & 0x01 && b[0] & 0x80)
105ret = fix;
106break;
107}
108*/
109return 0; //ret;
110}
111
112//----------------------------------------------------------------------------------
113
114static void fix_edid(unsigned char *edid, int fix)
115{
116unsigned char *b;
117
118switch (fix) {
119case FBMON_FIX_HEADER:
120msglog("EDID: trying a header reconstruct\n");
121memcpy(edid, edid_v1_header, 8);
122break;
123case FBMON_FIX_INPUT:
124msglog("EDID: trying to fix input type\n");
125b = edid + EDID_STRUCT_DISPLAY;
126b[0] &= ~0x80;
127edid[127] += 0x80;
128}
129}
130
131//----------------------------------------------------------------------------------
132
133int edid_checksum(unsigned char *edid)
134{
135unsigned char i, csum = 0, all_null = 0;
136int err = 0, fix = check_edid(edid);
137
138if (fix)
139fix_edid(edid, fix);
140
141for (i = 0; i < EDID_LENGTH; i++) {
142csum += edid[i];
143all_null |= edid[i];
144}
145
146if (csum == 0x00 && all_null) {
147/* checksum passed, everything's good */
148err = 1;
149}
150else
151{
152msglog(" edid_checksum error ");
153}
154
155return err;
156}
157
158//----------------------------------------------------------------------------------
159
160static int edid_check_header(unsigned char *edid)
161{
162int i, err = 1, fix = check_edid(edid);
163
164if (fix)
165fix_edid(edid, fix);
166
167for (i = 0; i < 8; i++) {
168if (edid[i] != edid_v1_header[i])
169err = 0;
170}
171
172if (err == 0)
173{
174msglog(" edid_check_header error ");
175}
176
177return err;
178}
179//------------------------------------------------------------------------
180bool verifyEDID(unsigned char *edid)
181{
182if (edid == NULL || !edid_checksum(edid) ||!edid_check_header(edid))
183{
184return false;
185}
186return true;
187}
188
189int edid_is_timing_block(unsigned char *block)
190{
191if ((block[0] != 0x00) || (block[1] != 0x00) || (block[2] != 0x00) || (block[4] != 0x00))
192{
193return 1;
194} else {
195return 0;
196}
197}
198//----------------------------------------------------------------------------------
199
200int fb_parse_edid(struct EDID *edid, edid_mode* var) //(struct EDID *edid, UInt32* x, UInt32* y)
201{
202int i;
203unsigned char *block;
204
205msglog(" Parse Edid:");
206if(!verifyEDID((unsigned char *)edid))
207{
208msglog(" error\n");
209return 0;
210}
211
212block = (unsigned char *)edid + DETAILED_TIMING_DESCRIPTIONS_START; //54
213
214for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
215if (edid_is_timing_block(block)) {
216msglog(" descriptor block %d is timing descriptor ", i);
217var->h_active = H_ACTIVE;
218var->v_active = V_ACTIVE;
219var->h_sync_offset = H_SYNC_OFFSET;
220var->h_sync_width = H_SYNC_WIDTH;
221var->h_blanking = H_BLANKING;
222var->v_blanking = V_BLANKING;
223var->pixel_clock = PIXEL_CLOCK;
224var->v_sync_offset = V_SYNC_OFFSET;
225var->v_sync_width = V_SYNC_WIDTH;
226/*
227var->xres = var->xres_virtual = H_ACTIVE;
228var->yres = var->yres_virtual = V_ACTIVE;
229var->height = var->width = -1;
230var->right_margin = H_SYNC_OFFSET;
231var->left_margin = (H_ACTIVE + H_BLANKING) -
232(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
233var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
234V_SYNC_WIDTH;
235var->lower_margin = V_SYNC_OFFSET;
236var->hsync_len = H_SYNC_WIDTH;
237var->vsync_len = V_SYNC_WIDTH;
238var->pixclock = PIXEL_CLOCK;
239var->pixclock /= 1000;
240var->pixclock = KHZ2PICOS(var->pixclock);
241
242if (HSYNC_POSITIVE)
243var->sync |= FB_SYNC_HOR_HIGH_ACT;
244if (VSYNC_POSITIVE)
245var->sync |= FB_SYNC_VERT_HIGH_ACT;
246 */
247return 1;
248}
249}
250return 0;
251}
252
253void getResolution(UInt32* x, UInt32* y, UInt32* bp)
254{
255//int val;
256static UInt32 xResolution, yResolution, bpResolution = 32;// assume 32bits
257/*
258if(getIntForKey(kScreenWidth, &val, &bootInfo->chameleonConfig))
259{
260xResolution = val;
261}
262
263if(getIntForKey(kScreenHeight, &val, &bootInfo->chameleonConfig))
264{
265yResolution = val;
266}
267*/
268if(!xResolution || !yResolution || !bpResolution)
269{
270char* edidInfo = readEDID();
271
272if(!edidInfo)
273{
274return;
275}
276
277edid_mode mode;
278// TODO: check *all* resolutions reported and either use the highest, or the native resolution (if there is a flag for that)
279//xResolution = edidInfo[56] | ((edidInfo[58] & 0xF0) << 4);
280//yResolution = edidInfo[59] | ((edidInfo[61] & 0xF0) << 4);
281//Slice - done here
282
283if(fb_parse_edid((struct EDID *)edidInfo, &mode) == 0)
284{
285xResolution = DEFAULT_SCREEN_WIDTH;
286yResolution = DEFAULT_SCREEN_HEIGHT;
287}
288else
289{
290xResolution = mode.h_active;
291yResolution = mode.v_active;
292}
293
294/*
295 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x32 0x0C
296 0x00 0xDF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0x00
297 0x0C 0xDF 0x00 0x00 0x12 0x03 0x21 0x78 0xE9 0x99
298 0x53 0x28 0xFF 0xFF 0x32 0xDF 0x00 0x12 0x80 0x78
299 0xD5 0x53 0x26 0x00 0x01 0x01 0x01 0x01 0xFF 0x00
300 0xDF 0x00 0x03 0x78 0x99 0x28 0x00 0x01 0x01 0x01
301 0x01 0x21 0x84 0x20 0xFF 0x0C 0x00 0x03 0x0A 0x53
302 0x54 0x01 0x01 0x01 0xDE 0x84 0x56 0x00 0xA0 0x30
303 0xFF 0xDF 0x12 0x78 0x53 0x00 0x01 0x01 0x01 0x84
304 0x00 0x18 0x84 0x00 0x00 0x57 0xFF 0x00 0x80 0x99
305 0x54 0x01 0x01 0x21 0x20 0x00 0x50 0x00 0x00 0x35
306 0x57 0xFE 0x00 0x00 0x78 0x28 0x01 0x01 0x21 0x20
307 0x18 0x30 0x00 0x57 0x34 0xFE 0xAA 0x9A
308
309 */
310
311//msglog("H Active = %d ", edidInfo[56] | ((edidInfo[58] & 0xF0) << 4) );
312//msglog("V Active = %d \n", edidInfo[59] | ((edidInfo[61] & 0xF0) << 4) );
313
314free( edidInfo );
315
316//if(!xResolution) xResolution = DEFAULT_SCREEN_WIDTH;
317//if(!yResolution) yResolution = DEFAULT_SCREEN_HEIGHT;
318
319}
320
321*x = xResolution;
322*y = yResolution;
323*bp = bpResolution;
324
325msglog("Best mode: %dx%dx%d\n", *x, *y, *bp);
326}
327
328char* readEDID()
329{
330SInt16 last_reported = -1;
331UInt8 edidInfo[EDID_BLOCK_SIZE];
332
333UInt8 header1[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
334UInt8 header2[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
335
336SInt16 status;
337UInt16 blocks_left = 1;
338//msglog("readEDID\n");
339do
340{
341// TODO: This currently only retrieves the *last* block, make the block buffer expand as needed / calculated from the first block
342
343bzero( edidInfo, EDID_BLOCK_SIZE);
344
345status = getEDID(edidInfo, blocks_left);
346
347/*
348msglog("Buffer location: 0x%X status: %d\n", SEG(edidInfo) << 16 | OFF(edidInfo), status);
349
350int j, i;
351for (j = 0; j < 8; j++)
352{
353for(i = 0; i < 16; i++) msglog(" 0x%02X", edidInfo[((i+1) * (j + 1)) - 1]);
354msglog("\n");
355}
356*/
357
358if(status == 0)
359{
360//if( edidInfo[0] == 0x00 || edidInfo[0] == 0xFF)
361if((memcmp(edidInfo, header1, sizeof(header1)) != 0) ||
362 (memcmp(edidInfo, header2, sizeof(header2)) != 0) )
363{
364blocks_left--;
365int reported = edidInfo[ EDID_V1_BLOCKS_TO_GO_OFFSET ];
366
367if ( reported > blocks_left )
368{
369msglog("EDID claims %d more blocks left\n", reported);
370}
371
372if ( (last_reported <= reported && last_reported != -1)
373|| reported == 0xff
374/* 0xff frequently comes up in corrupt edids */
375//|| reported == MAGIC
376)
377{
378msglog("Last reported %d\n", last_reported);
379msglog("EDID blocks left is wrong.\n"
380 "Your EDID is probably invalid.\n");
381return 0;
382}
383else
384{
385//printf("Reading EDID block\n");
386//printf("H Active = %d", ebiosInfo[56] | ((ebiosInfo[58] & 0xF0) << 4) );
387//printf("V Active = %d", ebiosInfo[59] | ((ebiosInfo[61] & 0xF0) << 4) );
388
389last_reported = reported;
390blocks_left = reported;
391}
392}
393else
394{
395msglog("Invalid block %d\n", blocks_left);
396msglog("Header1 = %d", memcmp(edidInfo, header1, sizeof(header1)) );
397msglog("Header2 = %d", memcmp(edidInfo, header2, sizeof(header2)) );
398return 0;
399}
400}
401blocks_left = 0;
402} while(blocks_left);
403
404char* ret = malloc(sizeof(edidInfo));
405if (!ret)
406{
407return 0;
408}
409memcpy(ret, edidInfo, sizeof(edidInfo));
410return ret;
411}
412
413int getEDID( void * edidBlock, UInt8 block)
414{
415biosBuf_t bb;
416bzero(&bb, sizeof(bb));
417bb.intno = 0x10;
418bb.eax.rr = 0x4F15;
419bb.ebx.r.l= 0x01;
420bb.edx.rr = block;
421bb.es = SEG( edidBlock );
422bb.edi.rr = OFF( edidBlock );
423bios( &bb );
424return(bb.eax.r.h);
425}
426

Archive Download this file

Revision: 2542