diff options
Diffstat (limited to 'drivers/video/fbmon.c')
-rw-r--r-- | drivers/video/fbmon.c | 37 |
1 files changed, 33 insertions, 4 deletions
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index b25399abcf49..4f57485f8c54 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -983,7 +983,8 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
983 | unsigned char *block; | 983 | unsigned char *block; |
984 | struct fb_videomode *m; | 984 | struct fb_videomode *m; |
985 | int num = 0, i; | 985 | int num = 0, i; |
986 | u8 edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; | 986 | u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; |
987 | u8 pos = 4, svd_n = 0; | ||
987 | 988 | ||
988 | if (!edid) | 989 | if (!edid) |
989 | return; | 990 | return; |
@@ -995,6 +996,21 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
995 | edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) | 996 | edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) |
996 | return; | 997 | return; |
997 | 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 | |||
998 | block = edid + edid[2]; | 1014 | block = edid + edid[2]; |
999 | 1015 | ||
1000 | DPRINTK(" Extended Detailed Timings\n"); | 1016 | DPRINTK(" Extended Detailed Timings\n"); |
@@ -1005,10 +1021,10 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
1005 | edt[num++] = block - edid; | 1021 | edt[num++] = block - edid; |
1006 | 1022 | ||
1007 | /* Yikes, EDID data is totally useless */ | 1023 | /* Yikes, EDID data is totally useless */ |
1008 | if (!num) | 1024 | if (!(num + svd_n)) |
1009 | return; | 1025 | return; |
1010 | 1026 | ||
1011 | m = kzalloc((specs->modedb_len + num) * | 1027 | m = kzalloc((specs->modedb_len + num + svd_n) * |
1012 | sizeof(struct fb_videomode), GFP_KERNEL); | 1028 | sizeof(struct fb_videomode), GFP_KERNEL); |
1013 | 1029 | ||
1014 | if (!m) | 1030 | if (!m) |
@@ -1023,9 +1039,22 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
1023 | pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); | 1039 | pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); |
1024 | } | 1040 | } |
1025 | 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 | |||
1026 | kfree(specs->modedb); | 1055 | kfree(specs->modedb); |
1027 | specs->modedb = m; | 1056 | specs->modedb = m; |
1028 | specs->modedb_len = specs->modedb_len + num; | 1057 | specs->modedb_len = specs->modedb_len + num + svd_n; |
1029 | } | 1058 | } |
1030 | 1059 | ||
1031 | /* | 1060 | /* |