diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2010-11-11 09:44:52 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-11-15 00:52:21 -0500 |
commit | e4105119aca9b86b163fa07428df1f615034a03d (patch) | |
tree | 2896d2accf7264ed04d71cc260803593fe4dabf9 /drivers | |
parent | 9fbbdde93231ad7f35c217aa6bbbc7995133f483 (diff) |
fbdev: export fb_edid_add_monspecs() for modules, improve algorithm
fb_edid_add_monspecs() should also be exported for use in modules, and it
requires a dummy version for the case, when CONFIG_FB_MODE_HELPERS is not
selected. This patch also improves the algorithm by removing a redundant
memory allocation, adds function documentation, adds data verification and
replaces memmove() with memcpy().
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/fbmon.c | 58 |
1 files changed, 30 insertions, 28 deletions
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index a0b5a93b72d2..b25399abcf49 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -973,58 +973,56 @@ 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 | */ | ||
976 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | 981 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) |
977 | { | 982 | { |
978 | unsigned char *block; | 983 | unsigned char *block; |
979 | struct fb_videomode *mode, *m; | 984 | struct fb_videomode *m; |
980 | int num = 0, i, first = 1; | 985 | int num = 0, i; |
986 | u8 edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; | ||
981 | 987 | ||
982 | if (edid == NULL) | 988 | if (!edid) |
983 | return; | 989 | return; |
984 | 990 | ||
985 | if (!edid_checksum(edid)) | 991 | if (!edid_checksum(edid)) |
986 | return; | 992 | return; |
987 | 993 | ||
988 | if (edid[0] != 0x2) | 994 | if (edid[0] != 0x2 || |
995 | edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) | ||
989 | return; | 996 | return; |
990 | 997 | ||
991 | mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); | 998 | block = edid + edid[2]; |
992 | if (mode == NULL) | ||
993 | return; | ||
994 | |||
995 | block = edid + edid[0x2]; | ||
996 | 999 | ||
997 | DPRINTK(" Extended Detailed Timings\n"); | 1000 | DPRINTK(" Extended Detailed Timings\n"); |
998 | 1001 | ||
999 | for (i = 0; i < (128 - edid[0x2]) / DETAILED_TIMING_DESCRIPTION_SIZE; | 1002 | for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE; |
1000 | i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { | 1003 | i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) |
1001 | if (!(block[0] == 0x00 && block[1] == 0x00)) { | 1004 | if (PIXEL_CLOCK) |
1002 | get_detailed_timing(block, &mode[num]); | 1005 | edt[num++] = block - edid; |
1003 | if (first) { | ||
1004 | mode[num].flag |= FB_MODE_IS_FIRST; | ||
1005 | first = 0; | ||
1006 | } | ||
1007 | num++; | ||
1008 | } | ||
1009 | } | ||
1010 | 1006 | ||
1011 | /* Yikes, EDID data is totally useless */ | 1007 | /* Yikes, EDID data is totally useless */ |
1012 | if (!num) { | 1008 | if (!num) |
1013 | kfree(mode); | ||
1014 | return; | 1009 | return; |
1015 | } | ||
1016 | 1010 | ||
1017 | m = kzalloc((specs->modedb_len + num) * | 1011 | m = kzalloc((specs->modedb_len + num) * |
1018 | sizeof(struct fb_videomode), GFP_KERNEL); | 1012 | sizeof(struct fb_videomode), GFP_KERNEL); |
1019 | 1013 | ||
1020 | if (!m) { | 1014 | if (!m) |
1021 | kfree(mode); | ||
1022 | return; | 1015 | return; |
1016 | |||
1017 | memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); | ||
1018 | |||
1019 | for (i = specs->modedb_len; i < specs->modedb_len + num; i++) { | ||
1020 | get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]); | ||
1021 | if (i == specs->modedb_len) | ||
1022 | m[i].flag |= FB_MODE_IS_FIRST; | ||
1023 | pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); | ||
1023 | } | 1024 | } |
1024 | 1025 | ||
1025 | memmove(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); | ||
1026 | memmove(m + specs->modedb_len, mode, num * sizeof(struct fb_videomode)); | ||
1027 | kfree(mode); | ||
1028 | kfree(specs->modedb); | 1026 | kfree(specs->modedb); |
1029 | specs->modedb = m; | 1027 | specs->modedb = m; |
1030 | specs->modedb_len = specs->modedb_len + num; | 1028 | specs->modedb_len = specs->modedb_len + num; |
@@ -1346,6 +1344,9 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
1346 | { | 1344 | { |
1347 | specs = NULL; | 1345 | specs = NULL; |
1348 | } | 1346 | } |
1347 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | ||
1348 | { | ||
1349 | } | ||
1349 | void fb_destroy_modedb(struct fb_videomode *modedb) | 1350 | void fb_destroy_modedb(struct fb_videomode *modedb) |
1350 | { | 1351 | { |
1351 | } | 1352 | } |
@@ -1453,6 +1454,7 @@ EXPORT_SYMBOL(fb_firmware_edid); | |||
1453 | 1454 | ||
1454 | EXPORT_SYMBOL(fb_parse_edid); | 1455 | EXPORT_SYMBOL(fb_parse_edid); |
1455 | EXPORT_SYMBOL(fb_edid_to_monspecs); | 1456 | EXPORT_SYMBOL(fb_edid_to_monspecs); |
1457 | EXPORT_SYMBOL(fb_edid_add_monspecs); | ||
1456 | EXPORT_SYMBOL(fb_get_mode); | 1458 | EXPORT_SYMBOL(fb_get_mode); |
1457 | EXPORT_SYMBOL(fb_validate_mode); | 1459 | EXPORT_SYMBOL(fb_validate_mode); |
1458 | EXPORT_SYMBOL(fb_destroy_modedb); | 1460 | EXPORT_SYMBOL(fb_destroy_modedb); |