diff options
Diffstat (limited to 'drivers/video/fbmon.c')
-rw-r--r-- | drivers/video/fbmon.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 563a98b88e9b..4f57485f8c54 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -973,6 +973,90 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
973 | DPRINTK("========================================\n"); | 973 | DPRINTK("========================================\n"); |
974 | } | 974 | } |
975 | 975 | ||
976 | /** | ||
977 | * fb_edid_add_monspecs() - add monitor video modes from E-EDID data | ||
978 | * @edid: 128 byte array with an E-EDID block | ||
979 | * @spacs: monitor specs to be extended | ||
980 | */ | ||
981 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | ||
982 | { | ||
983 | unsigned char *block; | ||
984 | struct fb_videomode *m; | ||
985 | int num = 0, i; | ||
986 | u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; | ||
987 | u8 pos = 4, svd_n = 0; | ||
988 | |||
989 | if (!edid) | ||
990 | return; | ||
991 | |||
992 | if (!edid_checksum(edid)) | ||
993 | return; | ||
994 | |||
995 | if (edid[0] != 0x2 || | ||
996 | edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) | ||
997 | return; | ||
998 | |||
999 | DPRINTK(" Short Video Descriptors\n"); | ||
1000 | |||
1001 | while (pos < edid[2]) { | ||
1002 | u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7; | ||
1003 | pr_debug("Data block %u of %u bytes\n", type, len); | ||
1004 | if (type == 2) | ||
1005 | for (i = pos; i < pos + len; i++) { | ||
1006 | u8 idx = edid[pos + i] & 0x7f; | ||
1007 | svd[svd_n++] = idx; | ||
1008 | pr_debug("N%sative mode #%d\n", | ||
1009 | edid[pos + i] & 0x80 ? "" : "on-n", idx); | ||
1010 | } | ||
1011 | pos += len + 1; | ||
1012 | } | ||
1013 | |||
1014 | block = edid + edid[2]; | ||
1015 | |||
1016 | DPRINTK(" Extended Detailed Timings\n"); | ||
1017 | |||
1018 | for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE; | ||
1019 | i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) | ||
1020 | if (PIXEL_CLOCK) | ||
1021 | edt[num++] = block - edid; | ||
1022 | |||
1023 | /* Yikes, EDID data is totally useless */ | ||
1024 | if (!(num + svd_n)) | ||
1025 | return; | ||
1026 | |||
1027 | m = kzalloc((specs->modedb_len + num + svd_n) * | ||
1028 | sizeof(struct fb_videomode), GFP_KERNEL); | ||
1029 | |||
1030 | if (!m) | ||
1031 | return; | ||
1032 | |||
1033 | memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); | ||
1034 | |||
1035 | for (i = specs->modedb_len; i < specs->modedb_len + num; i++) { | ||
1036 | get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]); | ||
1037 | if (i == specs->modedb_len) | ||
1038 | m[i].flag |= FB_MODE_IS_FIRST; | ||
1039 | pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); | ||
1040 | } | ||
1041 | |||
1042 | for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) { | ||
1043 | int idx = svd[i - specs->modedb_len - num]; | ||
1044 | if (!idx || idx > 63) { | ||
1045 | pr_warning("Reserved SVD code %d\n", idx); | ||
1046 | } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) { | ||
1047 | pr_warning("Unimplemented SVD code %d\n", idx); | ||
1048 | } else { | ||
1049 | memcpy(&m[i], cea_modes + idx, sizeof(m[i])); | ||
1050 | pr_debug("Adding SVD #%d: %ux%u@%u\n", idx, | ||
1051 | m[i].xres, m[i].yres, m[i].refresh); | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | kfree(specs->modedb); | ||
1056 | specs->modedb = m; | ||
1057 | specs->modedb_len = specs->modedb_len + num + svd_n; | ||
1058 | } | ||
1059 | |||
976 | /* | 1060 | /* |
977 | * VESA Generalized Timing Formula (GTF) | 1061 | * VESA Generalized Timing Formula (GTF) |
978 | */ | 1062 | */ |
@@ -1289,6 +1373,9 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
1289 | { | 1373 | { |
1290 | specs = NULL; | 1374 | specs = NULL; |
1291 | } | 1375 | } |
1376 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | ||
1377 | { | ||
1378 | } | ||
1292 | void fb_destroy_modedb(struct fb_videomode *modedb) | 1379 | void fb_destroy_modedb(struct fb_videomode *modedb) |
1293 | { | 1380 | { |
1294 | } | 1381 | } |
@@ -1396,6 +1483,7 @@ EXPORT_SYMBOL(fb_firmware_edid); | |||
1396 | 1483 | ||
1397 | EXPORT_SYMBOL(fb_parse_edid); | 1484 | EXPORT_SYMBOL(fb_parse_edid); |
1398 | EXPORT_SYMBOL(fb_edid_to_monspecs); | 1485 | EXPORT_SYMBOL(fb_edid_to_monspecs); |
1486 | EXPORT_SYMBOL(fb_edid_add_monspecs); | ||
1399 | EXPORT_SYMBOL(fb_get_mode); | 1487 | EXPORT_SYMBOL(fb_get_mode); |
1400 | EXPORT_SYMBOL(fb_validate_mode); | 1488 | EXPORT_SYMBOL(fb_validate_mode); |
1401 | EXPORT_SYMBOL(fb_destroy_modedb); | 1489 | EXPORT_SYMBOL(fb_destroy_modedb); |