*␊ |
* Created by Evan Lojewski on 12/1/09.␊ |
* Copyright 2009. All rights reserved.␊ |
*␊ |
* ␊ |
*␉Slice 2010␊ |
*/␊ |
␊ |
␊ |
|
#include "vbe.h"␊ |
#include "graphics.h"␊ |
#include "boot.h"␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
␊ |
#define FBMON_FIX_HEADER 1␊ |
#define FBMON_FIX_INPUT 2␊ |
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
/*␊ |
struct broken_edid {␊ |
␉const char manufacturer[4];␊ |
␉UInt32 model;␊ |
␉UInt32 fix;␊ |
};␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
␊ |
broken_edid brokendb[] = {␊ |
␉// DEC FR-PCXAV-YZ *␊ |
␉{ "DEC", 0x073a, FBMON_FIX_HEADER,},␊ |
␉// ViewSonic PF775a *␊ |
␉{ "VSC", 0x5a44, FBMON_FIX_INPUT,␉}␊ |
};␊ |
//----------------------------------------------------------------------------------␊ |
*/␊ |
const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00␉};␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
int edid_compare(unsigned char *edid1, unsigned char *edid2)␊ |
{␊ |
␉int result = 0;␊ |
␉unsigned char *block = edid1 + ID_MANUFACTURER_NAME, manufacturer1[4], manufacturer2[4];;␊ |
␉manufacturer1[0] = ((block[0] & 0x7c) >> 2) + '@';␊ |
␉manufacturer1[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';␊ |
␉manufacturer1[2] = (block[1] & 0x1f) + '@';␊ |
␉manufacturer1[3] = 0;␊ |
␉␊ |
␉block = edid2 + ID_MANUFACTURER_NAME;␊ |
␉manufacturer2[0] = ((block[0] & 0x7c) >> 2) + '@';␊ |
␉manufacturer2[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';␊ |
␉manufacturer2[2] = (block[1] & 0x1f) + '@';␊ |
␉manufacturer2[3] = 0;␊ |
␉int x;␊ |
␉for(x = 0; x < 4; x++)␊ |
␉{␊ |
␉␉if(manufacturer1[x] == manufacturer2[x])␊ |
␉␉␉result++;␊ |
␉}␊ |
␉␊ |
␉return result;␊ |
}␊ |
␊ |
int check_edid(unsigned char *edid)␊ |
{␊ |
␉unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];␊ |
␉//unsigned char *b;␊ |
␉UInt32 model;␊ |
␉//int i, fix = 0, ret = 0;␊ |
␉␊ |
␉manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';␊ |
␉manufacturer[1] = ((block[0] & 0x03) << 3) +␊ |
␉((block[1] & 0xe0) >> 5) + '@';␊ |
␉manufacturer[2] = (block[1] & 0x1f) + '@';␊ |
␉manufacturer[3] = 0;␊ |
␉model = block[2] + (block[3] << 8);␊ |
/*␉␊ |
␉for (i = 0; i < (int)ARRAY_SIZE(brokendb); i++) {␊ |
␉␉if (!strncmp((const char *)manufacturer, brokendb[i].manufacturer, 4) &&␊ |
␉␉␉brokendb[i].model == model) {␊ |
␉␉␉DEBG("ATIFB: The EDID Block of "␊ |
␉␉␉␉ "Manufacturer: %s Model: 0x%08lx is known to "␊ |
␉␉␉␉ "be broken,\n", manufacturer, model);␊ |
␉␉␉fix = brokendb[i].fix;␊ |
␉␉␉break;␊ |
␉␉}␊ |
␉}␊ |
␉␊ |
␉switch (fix) {␊ |
␉␉case FBMON_FIX_HEADER:␊ |
␉␉␉for (i = 0; i < 8; i++) {␊ |
␉␉␉␉if (edid[i] != edid_v1_header[i])␊ |
␉␉␉␉␉ret = fix;␊ |
␉␉␉}␊ |
␉␉␉break;␊ |
␉␉case FBMON_FIX_INPUT:␊ |
␉␉␉b = edid + EDID_STRUCT_DISPLAY;␊ |
␉␉␉/// Only if display is GTF capable will␊ |
␉␉␉ //the input type be reset to analog *␊ |
␉␉␉if (b[4] & 0x01 && b[0] & 0x80)␊ |
␉␉␉␉ret = fix;␊ |
␉␉␉break;␊ |
␉}␊ |
*/␉␊ |
␉return 0; //ret;␊ |
}␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
␊ |
static void fix_edid(unsigned char *edid, int fix)␊ |
{␊ |
␉unsigned char *b;␊ |
␉␊ |
␉switch (fix) {␊ |
␉␉case FBMON_FIX_HEADER:␊ |
␉␉␉msglog("EDID: trying a header reconstruct\n");␊ |
␉␉␉memcpy(edid, edid_v1_header, 8);␊ |
␉␉␉break;␊ |
␉␉case FBMON_FIX_INPUT:␊ |
␉␉␉msglog("EDID: trying to fix input type\n");␊ |
␉␉␉b = edid + EDID_STRUCT_DISPLAY;␊ |
␉␉␉b[0] &= ~0x80;␊ |
␉␉␉edid[127] += 0x80;␊ |
␉}␊ |
}␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
␊ |
int edid_checksum(unsigned char *edid)␊ |
{␊ |
␉unsigned char i, csum = 0, all_null = 0;␊ |
␉int err = 0, fix = check_edid(edid);␊ |
␉␊ |
␉if (fix)␊ |
␉␉fix_edid(edid, fix);␊ |
␉␊ |
␉for (i = 0; i < EDID_LENGTH; i++) {␊ |
␉␉csum += edid[i];␊ |
␉␉all_null |= edid[i];␊ |
␉}␊ |
␉␊ |
␉if (csum == 0x00 && all_null) {␊ |
␉␉/* checksum passed, everything's good */␊ |
␉␉err = 1;␊ |
␉}␊ |
␉␊ |
␉return err;␊ |
}␊ |
␊ |
//----------------------------------------------------------------------------------␊ |
␊ |
static int edid_check_header(unsigned char *edid)␊ |
{␊ |
␉int i, err = 1, fix = check_edid(edid);␊ |
␉␊ |
␉if (fix)␊ |
␉␉fix_edid(edid, fix);␊ |
␉␊ |
␉for (i = 0; i < 8; i++) {␊ |
␉␉if (edid[i] != edid_v1_header[i])␊ |
␉␉␉err = 0;␊ |
␉}␊ |
␉␊ |
␉return err;␊ |
}␊ |
//------------------------------------------------------------------------␊ |
bool verifyEDID(unsigned char *edid)␊ |
{␊ |
␉if (edid == NULL || !edid_checksum(edid) ||␉!edid_check_header(edid)) ␊ |
␉{␊ |
␉␉return false;␊ |
␉}␊ |
␉return true;␊ |
}␊ |
␊ |
int edid_is_timing_block(unsigned char *block)␊ |
{␊ |
␉if ((block[0] != 0x00) || (block[1] != 0x00) ||␊ |
␉␉(block[2] != 0x00) || (block[4] != 0x00))␊ |
␉␉return 1;␊ |
␉else␊ |
␉␉return 0;␊ |
}␊ |
//----------------------------------------------------------------------------------␊ |
␊ |
int fb_parse_edid(struct EDID *edid, UInt32* x, UInt32* y)␊ |
{␊ |
␉int i;␊ |
␉unsigned char *block;␊ |
␉␊ |
␉if(!verifyEDID((unsigned char *)edid)) return 1;␊ |
␉␊ |
␉block = (unsigned char *)edid + DETAILED_TIMING_DESCRIPTIONS_START; //54␊ |
␉␊ |
␉for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {␊ |
␉␉if (edid_is_timing_block(block)) {␊ |
␉␉␉*x = H_ACTIVE;␊ |
␉␉␉*y = V_ACTIVE;␊ |
␉␉␉/*␊ |
␉␉␉var->xres = var->xres_virtual = H_ACTIVE;␊ |
␉␉␉var->yres = var->yres_virtual = V_ACTIVE;␊ |
␉␉␉var->height = var->width = -1;␊ |
␉␉␉var->right_margin = H_SYNC_OFFSET;␊ |
␉␉␉var->left_margin = (H_ACTIVE + H_BLANKING) -␊ |
␉␉␉(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);␊ |
␉␉␉var->upper_margin = V_BLANKING - V_SYNC_OFFSET -␊ |
␉␉␉V_SYNC_WIDTH;␊ |
␉␉␉var->lower_margin = V_SYNC_OFFSET;␊ |
␉␉␉var->hsync_len = H_SYNC_WIDTH;␊ |
␉␉␉var->vsync_len = V_SYNC_WIDTH;␊ |
␉␉␉var->pixclock = PIXEL_CLOCK;␊ |
␉␉␉var->pixclock /= 1000;␊ |
␉␉␉var->pixclock = KHZ2PICOS(var->pixclock);␊ |
␉␉␉␊ |
␉␉␉if (HSYNC_POSITIVE)␊ |
␉␉␉␉var->sync |= FB_SYNC_HOR_HIGH_ACT;␊ |
␉␉␉if (VSYNC_POSITIVE)␊ |
␉␉␉␉var->sync |= FB_SYNC_VERT_HIGH_ACT;␊ |
␉␉␉ */␊ |
␉␉␉return 0;␊ |
␉␉}␊ |
␉}␊ |
␉return 1;␊ |
}␊ |
␊ |
void getResolution(UInt32* x, UInt32* y, UInt32* bp)␊ |
{␊ |
␉int val;␊ |
|
␉␉if(!edidInfo) return;␊ |
␉␉␊ |
␉␉// TODO: check *all* resolutions reported and either use the highest, or the native resolution (if there is a flag for that)␊ |
␉␉xResolution = edidInfo[56] | ((edidInfo[58] & 0xF0) << 4);␊ |
␉␉yResolution = edidInfo[59] | ((edidInfo[61] & 0xF0) << 4);␊ |
␉␉//xResolution = edidInfo[56] | ((edidInfo[58] & 0xF0) << 4); ␊ |
␉␉//yResolution = edidInfo[59] | ((edidInfo[61] & 0xF0) << 4); ␊ |
␉␉if(fb_parse_edid(edidInfo, &xResolution, &yResolution))␊ |
␉␉{␊ |
␉␉␉xResolution = DEFAULT_SCREEN_WIDTH;␊ |
␉␉␉yResolution = DEFAULT_SCREEN_HEIGHT;␊ |
␉␉}␊ |
␉␉/*␊ |
␉␉ 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x32 0x0C␊ |
␉␉ 0x00 0xDF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0x00␊ |
␉␉ 0x0C 0xDF 0x00 0x00 0x12 0x03 0x21 0x78 0xE9 0x99 ␊ |
␉␉ 0x53 0x28 0xFF 0xFF 0x32 0xDF 0x00 0x12 0x80 0x78 ␊ |
␉␉ 0xD5 0x53 0x26 0x00 0x01 0x01 0x01 0x01 0xFF 0x00 ␊ |
␉␉ 0xDF 0x00 0x03 0x78 0x99 0x28 0x00 0x01 0x01 0x01 ␊ |
␉␉ 0x01 0x21 0x84 0x20 0xFF 0x0C 0x00 0x03 0x0A 0x53 ␊ |
␉␉ 0x54 0x01 0x01 0x01 0xDE 0x84 0x56 0x00 0xA0 0x30␊ |
␉␉ 0xFF 0xDF 0x12 0x78 0x53 0x00 0x01 0x01 0x01 0x84 ␊ |
␉␉ 0x00 0x18 0x84 0x00 0x00 0x57 0xFF 0x00 0x80 0x99␊ |
␉␉ 0x54 0x01 0x01 0x21 0x20 0x00 0x50 0x00 0x00 0x35␊ |
␉␉ 0x57 0xFE 0x00 0x00 0x78 0x28 0x01 0x01 0x21 0x20␊ |
␉␉ 0x18 0x30 0x00 0x57 0x34 0xFE 0xAA 0x9A ␊ |
␊ |
␉␉ */␊ |
␉␉␊ |
␉␉//printf("H Active = %d", edidInfo[56] | ((edidInfo[58] & 0xF0) << 4) );␊ |
␉␉//printf("V Active = %d", edidInfo[59] | ((edidInfo[61] & 0xF0) << 4) );␊ |
␉␉//msglog("H Active = %d ", edidInfo[56] | ((edidInfo[58] & 0xF0) << 4) );␊ |
␉␉//msglog("V Active = %d \n", edidInfo[59] | ((edidInfo[61] & 0xF0) << 4) );␊ |
␉␉␊ |
␉␉free( edidInfo );␊ |
␉␉␊ |
␉␉if(!xResolution) xResolution = DEFAULT_SCREEN_WIDTH;␊ |
␉␉if(!yResolution) yResolution = DEFAULT_SCREEN_HEIGHT;␊ |
␉␉//if(!xResolution) xResolution = DEFAULT_SCREEN_WIDTH;␊ |
␉␉//if(!yResolution) yResolution = DEFAULT_SCREEN_HEIGHT;␊ |
␊ |
␉}␊ |
␊ |
|
␉␊ |
␉SInt16 status;␊ |
␉UInt16 blocks_left = 1;␊ |
␉␊ |
␉msglog("readEDID\n");␊ |
␉do␊ |
␉{␊ |
␉␉// TODO: This currently only retrieves the *last* block, make the block buffer expand as needed / calculated from the first block␊ |
|
␉␉status = getEDID(edidInfo, blocks_left);␊ |
␉␉␊ |
␉␉␊ |
␉␉//printf("Buffer location: 0x%X\n", SEG(buffer) << 16 | OFF(buffer));␊ |
␉␉/*␊ |
␉␉msglog("Buffer location: 0x%X status: %d\n", SEG(edidInfo) << 16 | OFF(edidInfo), status);␊ |
␉␉␊ |
␉␉int j, i;␊ |
␉␉for (j = 0; j < 8; j++) {␊ |
␉␉␉for(i = 0; i < 16; i++) printf("0x%X ", ebiosInfo[((i+1) * (j + 1)) - 1]);␊ |
␊ |
␉␉␉for(i = 0; i < 16; i++) msglog("0x%02X ", edidInfo[((i+1) * (j + 1)) - 1]);␊ |
␉␉␉msglog("\n");␊ |
␉␉}␊ |
␉␉printf("\n");␊ |
␉␉*/␊ |
␉␉␊ |
␉␉␊ |
␉␉␊ |
␉␉if(status == 0)␊ |
␉␉{␊ |
␉␉␉//if( edidInfo[0] == 0x00 || edidInfo[0] == 0xFF)␊ |
|
␉␉␉␉if ( reported > blocks_left )␊ |
␉␉␉␉{␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉verbose("EDID claims %d more blocks left\n", reported);␊ |
␉␉␉␉␉msglog("EDID claims %d more blocks left\n", reported);␊ |
␉␉␉␉}␊ |
␉␉␉␉␊ |
␉␉␉␉if ( (last_reported <= reported && last_reported != -1)␊ |
|
␉␉␉␉␉//|| reported == MAGIC␊ |
␉␉␉␉␉)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉verbose("Last reported %d\n", last_reported);␊ |
␉␉␉␉␉verbose( "EDID blocks left is wrong.\n"␊ |
␉␉␉␉␉msglog("Last reported %d\n", last_reported);␊ |
␉␉␉␉␉msglog( "EDID blocks left is wrong.\n"␊ |
␉␉␉␉␉␉ "Your EDID is probably invalid.\n");␊ |
␉␉␉␉␉return 0;␊ |
␉␉␉␉}␊ |
|
␉␉␉} ␊ |
␉␉␉else␊ |
␉␉␉{␊ |
␉␉␉␉verbose("Invalid block %d\n", blocks_left);␊ |
␉␉␉␉verbose("Header1 = %d", memcmp(edidInfo, header1, sizeof(header1)) );␊ |
␉␉␉␉verbose("Header2 = %d", memcmp(edidInfo, header2, sizeof(header2)) );␊ |
␉␉␉␉msglog("Invalid block %d\n", blocks_left);␊ |
␉␉␉␉msglog("Header1 = %d", memcmp(edidInfo, header1, sizeof(header1)) );␊ |
␉␉␉␉msglog("Header2 = %d", memcmp(edidInfo, header2, sizeof(header2)) );␊ |
␉␉␉␉return 0;␊ |
␉␉␉}␊ |
␉␉}␊ |