summaryrefslogtreecommitdiff
path: root/src/lib/edid.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/edid.c')
-rw-r--r--src/lib/edid.c123
1 files changed, 71 insertions, 52 deletions
diff --git a/src/lib/edid.c b/src/lib/edid.c
index db0f412ba2..e08535dd7a 100644
--- a/src/lib/edid.c
+++ b/src/lib/edid.c
@@ -68,20 +68,43 @@ struct edid_context {
int conformant;
};
+/* Stuff that isn't used anywhere but is nice to pretty-print while
+ we're decoding everything else. */
+static struct {
+ char manuf_name[4];
+ unsigned int model;
+ unsigned int serial;
+ unsigned int year;
+ unsigned int week;
+ unsigned int version[2];
+ unsigned int nonconformant;
+ unsigned int type;
+
+ unsigned int x_mm;
+ unsigned int y_mm;
+
+ unsigned int voltage;
+ unsigned int sync;
+
+ const char *syncmethod;
+ const char *range_class;
+ const char *stereo;
+} extra_info;
+
static int vbe_valid;
static struct lb_framebuffer edid_fb;
-static char *manufacturer_name(struct edid *out, unsigned char *x)
+static char *manufacturer_name(unsigned char *x)
{
- out->manuf_name[0] = ((x[0] & 0x7C) >> 2) + '@';
- out->manuf_name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xE0) >> 5) + '@';
- out->manuf_name[2] = (x[1] & 0x1F) + '@';
- out->manuf_name[3] = 0;
+ extra_info.manuf_name[0] = ((x[0] & 0x7C) >> 2) + '@';
+ extra_info.manuf_name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xE0) >> 5) + '@';
+ extra_info.manuf_name[2] = (x[1] & 0x1F) + '@';
+ extra_info.manuf_name[3] = 0;
- if (isupper(out->manuf_name[0]) &&
- isupper(out->manuf_name[1]) &&
- isupper(out->manuf_name[2]))
- return out->manuf_name;
+ if (isupper(extra_info.manuf_name[0]) &&
+ isupper(extra_info.manuf_name[1]) &&
+ isupper(extra_info.manuf_name[2]))
+ return extra_info.manuf_name;
return NULL;
}
@@ -258,7 +281,7 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
int v_max_offset = 0, v_min_offset = 0;
int is_cvt = 0;
c->has_range_descriptor = 1;
- out->range_class = "";
+ extra_info.range_class = "";
/*
* XXX todo: implement feature flags, vtd blocks
* XXX check: ranges are well-formed; block termination if no vtd
@@ -285,25 +308,25 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
*/
switch (x[10]) {
case 0x00: /* default gtf */
- out->range_class = "GTF";
+ extra_info.range_class = "GTF";
break;
case 0x01: /* range limits only */
- out->range_class = "bare limits";
+ extra_info.range_class = "bare limits";
if (!c->claims_one_point_four)
c->has_valid_range_descriptor = 0;
break;
case 0x02: /* secondary gtf curve */
- out->range_class = "GTF with icing";
+ extra_info.range_class = "GTF with icing";
break;
case 0x04: /* cvt */
- out->range_class = "CVT";
+ extra_info.range_class = "CVT";
is_cvt = 1;
if (!c->claims_one_point_four)
c->has_valid_range_descriptor = 0;
break;
default: /* invalid */
c->has_valid_range_descriptor = 0;
- out->range_class = "invalid";
+ extra_info.range_class = "invalid";
break;
}
@@ -312,7 +335,7 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
if (x[7] + h_min_offset > x[8] + h_max_offset)
c->has_valid_range_descriptor = 0;
printk(BIOS_SPEW, "Monitor ranges (%s): %d-%dHz V, %d-%dkHz H",
- out->range_class,
+ extra_info.range_class,
x[5] + v_min_offset, x[6] + v_max_offset,
x[7] + h_min_offset, x[8] + h_max_offset);
if (x[9])
@@ -423,8 +446,8 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
if (! c->did_detailed_timing){
/* Edid contains pixel clock in terms of 10KHz */
out->pixel_clock = (x[0] + (x[1] << 8)) * 10;
- out->x_mm = (x[12] + ((x[14] & 0xF0) << 4));
- out->y_mm = (x[13] + ((x[14] & 0x0F) << 8));
+ extra_info.x_mm = (x[12] + ((x[14] & 0xF0) << 4));
+ extra_info.y_mm = (x[13] + ((x[14] & 0x0F) << 8));
out->ha = (x[2] + ((x[4] & 0xF0) << 4));
out->hbl = (x[3] + ((x[4] & 0x0F) << 8));
out->hso = (x[8] + ((x[11] & 0xC0) << 2));
@@ -464,41 +487,41 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
c->did_detailed_timing = 1;
switch ((x[17] & 0x18) >> 3) {
case 0x00:
- out->syncmethod = " analog composite";
+ extra_info.syncmethod = " analog composite";
break;
case 0x01:
- out->syncmethod = " bipolar analog composite";
+ extra_info.syncmethod = " bipolar analog composite";
break;
case 0x02:
- out->syncmethod = " digital composite";
+ extra_info.syncmethod = " digital composite";
break;
case 0x03:
- out->syncmethod = "";
+ extra_info.syncmethod = "";
break;
}
out->pvsync = (x[17] & (1 << 2)) ? '+' : '-';
out->phsync = (x[17] & (1 << 1)) ? '+' : '-';
switch (x[17] & 0x61) {
case 0x20:
- out->stereo = "field sequential L/R";
+ extra_info.stereo = "field sequential L/R";
break;
case 0x40:
- out->stereo = "field sequential R/L";
+ extra_info.stereo = "field sequential R/L";
break;
case 0x21:
- out->stereo = "interleaved right even";
+ extra_info.stereo = "interleaved right even";
break;
case 0x41:
- out->stereo = "interleaved left even";
+ extra_info.stereo = "interleaved left even";
break;
case 0x60:
- out->stereo = "four way interleaved";
+ extra_info.stereo = "four way interleaved";
break;
case 0x61:
- out->stereo = "side by side interleaved";
+ extra_info.stereo = "side by side interleaved";
break;
default:
- out->stereo = "";
+ extra_info.stereo = "";
break;
}
@@ -507,16 +530,16 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
" %04x %04x %04x %04x vborder %x\n"
" %chsync %cvsync%s%s %s\n",
out->pixel_clock,
- out->x_mm,
- out->y_mm,
+ extra_info.x_mm,
+ extra_info.y_mm,
out->ha, out->ha + out->hso, out->ha + out->hso + out->hspw,
out->ha + out->hbl, out->hborder,
out->va, out->va + out->vso, out->va + out->vso + out->vspw,
out->va + out->vbl, out->vborder,
out->phsync, out->pvsync,
- out->syncmethod, x[17] & 0x80 ?" interlaced" : "",
- out->stereo
- );
+ extra_info.syncmethod, x[17] & 0x80 ?" interlaced" : "",
+ extra_info.stereo
+ );
return 1;
}
@@ -983,15 +1006,15 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
}
memset(out, 0, sizeof(*out));
- if (manufacturer_name(out, edid + 0x08))
+ if (manufacturer_name(edid + 0x08))
c.manufacturer_name_well_formed = 1;
- out->model = (unsigned short)(edid[0x0A] + (edid[0x0B] << 8));
- out->serial = (unsigned int)(edid[0x0C] + (edid[0x0D] << 8)
+ extra_info.model = (unsigned short)(edid[0x0A] + (edid[0x0B] << 8));
+ extra_info.serial = (unsigned int)(edid[0x0C] + (edid[0x0D] << 8)
+ (edid[0x0E] << 16) + (edid[0x0F] << 24));
printk(BIOS_SPEW, "Manufacturer: %s Model %x Serial Number %u\n",
- out->manuf_name,
+ extra_info.manuf_name,
(unsigned short)(edid[0x0A] + (edid[0x0B] << 8)),
(unsigned int)(edid[0x0C] + (edid[0x0D] << 8)
+ (edid[0x0E] << 16) + (edid[0x0F] << 24)));
@@ -1004,24 +1027,24 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
c.has_valid_year = 1;
printk(BIOS_SPEW, "Made week %hhd of model year %hhd\n", edid[0x10],
edid[0x11]);
- out->week = edid[0x10];
- out->year = edid[0x11];
+ extra_info.week = edid[0x10];
+ extra_info.year = edid[0x11];
} else {
/* we know it's at least 2013, when this code was written */
if (edid[0x11] + 90 <= 2013) {
c.has_valid_year = 1;
printk(BIOS_SPEW, "Made week %hhd of %d\n",
edid[0x10], edid[0x11] + 1990);
- out->week = edid[0x10];
- out->year = edid[0x11] + 1990;
+ extra_info.week = edid[0x10];
+ extra_info.year = edid[0x11] + 1990;
}
}
}
}
printk(BIOS_SPEW, "EDID version: %hhd.%hhd\n", edid[0x12], edid[0x13]);
- out->version[0] = edid[0x12];
- out->version[1] = edid[0x13];
+ extra_info.version[0] = edid[0x12];
+ extra_info.version[1] = edid[0x13];
if (edid[0x12] == 1) {
if (edid[0x13] > 4) {
@@ -1068,7 +1091,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
default:
c.nonconformant_digital_display = 1;
}
- out->type = edid[0x14] & 0x0f;
+ extra_info.type = edid[0x14] & 0x0f;
} else if (c.claims_one_point_two) {
conformance_mask = 0x7E;
if (edid[0x14] & 0x01) {
@@ -1079,13 +1102,13 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
if (!c.nonconformant_digital_display)
c.nonconformant_digital_display = edid[0x14] & conformance_mask;
- out->nonconformant = c.nonconformant_digital_display;
+ extra_info.nonconformant = c.nonconformant_digital_display;
} else {
analog = 1;
int voltage = (edid[0x14] & 0x60) >> 5;
int sync = (edid[0x14] & 0x0F);
- out->voltage = voltage;
- out->sync = sync;
+ extra_info.voltage = voltage;
+ extra_info.sync = sync;
printk(BIOS_SPEW, "Analog display, Input voltage level: %s V\n",
voltage == 3 ? "0.7/0.7" :
@@ -1117,19 +1140,15 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
if (edid[0x15] && edid[0x16]) {
printk(BIOS_SPEW, "Maximum image size: %d cm x %d cm\n",
edid[0x15], edid[0x16]);
- out->xsize_cm = edid[0x15];
- out->ysize_cm = edid[0x16];
} else if (c.claims_one_point_four && (edid[0x15] || edid[0x16])) {
if (edid[0x15]) { /* edid[0x15] != 0 && edid[0x16] == 0 */
unsigned int ratio = 100000/(edid[0x15] + 99);
printk(BIOS_SPEW, "Aspect ratio is %u.%03u (landscape)\n",
ratio / 1000, ratio % 1000);
- out->aspect_landscape = ratio / 100;
} else { /* edid[0x15] == 0 && edid[0x16] != 0 */
unsigned int ratio = 100000/(edid[0x16] + 99);
printk(BIOS_SPEW, "Aspect ratio is %u.%03u (portrait)\n",
ratio / 1000, ratio % 1000);
- out->aspect_portrait = ratio / 100;
}
} else {
/* Either or both can be zero for 1.3 and before */