diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2009-04-06 22:01:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 11:31:09 -0400 |
commit | 215059d2421f95c30d1fca6ff31357fcae9f67dc (patch) | |
tree | 7eadb76ba99372f4674e46c8553639ba11a529cf /drivers/video/tdfxfb.c | |
parent | feff3880d06da0cc8fc65b9e40f518fea7594674 (diff) |
tdfxfb: make use of DDC information about connected monitor
Read DDC information from a connected monitor and use it to select initial
mode (if the mode is not specified).
Also, use the information to protect against modes outside the monitor
specs.
Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Tested-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/tdfxfb.c')
-rw-r--r-- | drivers/video/tdfxfb.c | 67 |
1 files changed, 63 insertions, 4 deletions
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index bc6f916c53be..89f231dc443f 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c | |||
@@ -487,6 +487,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
487 | return -EINVAL; | 487 | return -EINVAL; |
488 | } | 488 | } |
489 | 489 | ||
490 | if (info->monspecs.hfmax && info->monspecs.vfmax && | ||
491 | info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) { | ||
492 | DPRINTK("mode outside monitor's specs\n"); | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
490 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ | 496 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ |
491 | lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); | 497 | lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); |
492 | 498 | ||
@@ -1355,6 +1361,23 @@ static void tdfxfb_delete_i2c_busses(struct tdfx_par *par) | |||
1355 | i2c_del_adapter(&par->chan[1].adapter); | 1361 | i2c_del_adapter(&par->chan[1].adapter); |
1356 | par->chan[1].par = NULL; | 1362 | par->chan[1].par = NULL; |
1357 | } | 1363 | } |
1364 | |||
1365 | static int tdfxfb_probe_i2c_connector(struct tdfx_par *par, | ||
1366 | struct fb_monspecs *specs) | ||
1367 | { | ||
1368 | u8 *edid = NULL; | ||
1369 | |||
1370 | DPRINTK("Probe DDC Bus\n"); | ||
1371 | if (par->chan[0].par) | ||
1372 | edid = fb_ddc_read(&par->chan[0].adapter); | ||
1373 | |||
1374 | if (edid) { | ||
1375 | fb_edid_to_monspecs(edid, specs); | ||
1376 | kfree(edid); | ||
1377 | return 0; | ||
1378 | } | ||
1379 | return 1; | ||
1380 | } | ||
1358 | #endif /* CONFIG_FB_3DFX_I2C */ | 1381 | #endif /* CONFIG_FB_3DFX_I2C */ |
1359 | 1382 | ||
1360 | /** | 1383 | /** |
@@ -1372,6 +1395,8 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1372 | struct tdfx_par *default_par; | 1395 | struct tdfx_par *default_par; |
1373 | struct fb_info *info; | 1396 | struct fb_info *info; |
1374 | int err, lpitch; | 1397 | int err, lpitch; |
1398 | struct fb_monspecs *specs; | ||
1399 | bool found; | ||
1375 | 1400 | ||
1376 | err = pci_enable_device(pdev); | 1401 | err = pci_enable_device(pdev); |
1377 | if (err) { | 1402 | if (err) { |
@@ -1474,15 +1499,49 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1474 | if (hwcursor) | 1499 | if (hwcursor) |
1475 | info->fix.smem_len = (info->fix.smem_len - 1024) & | 1500 | info->fix.smem_len = (info->fix.smem_len - 1024) & |
1476 | (PAGE_MASK << 1); | 1501 | (PAGE_MASK << 1); |
1502 | specs = &info->monspecs; | ||
1503 | found = false; | ||
1504 | info->var.bits_per_pixel = 8; | ||
1477 | #ifdef CONFIG_FB_3DFX_I2C | 1505 | #ifdef CONFIG_FB_3DFX_I2C |
1478 | tdfxfb_create_i2c_busses(info); | 1506 | tdfxfb_create_i2c_busses(info); |
1507 | err = tdfxfb_probe_i2c_connector(default_par, specs); | ||
1508 | |||
1509 | if (!err) { | ||
1510 | if (specs->modedb == NULL) | ||
1511 | DPRINTK("Unable to get Mode Database\n"); | ||
1512 | else { | ||
1513 | const struct fb_videomode *m; | ||
1514 | |||
1515 | fb_videomode_to_modelist(specs->modedb, | ||
1516 | specs->modedb_len, | ||
1517 | &info->modelist); | ||
1518 | m = fb_find_best_display(specs, &info->modelist); | ||
1519 | if (m) { | ||
1520 | fb_videomode_to_var(&info->var, m); | ||
1521 | /* fill all other info->var's fields */ | ||
1522 | if (tdfxfb_check_var(&info->var, info) < 0) | ||
1523 | info->var = tdfx_var; | ||
1524 | else | ||
1525 | found = true; | ||
1526 | } | ||
1527 | } | ||
1528 | } | ||
1479 | #endif | 1529 | #endif |
1480 | if (!mode_option) | 1530 | if (!mode_option && !found) |
1481 | mode_option = "640x480@60"; | 1531 | mode_option = "640x480@60"; |
1482 | 1532 | ||
1483 | err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); | 1533 | if (mode_option) { |
1484 | if (!err || err == 4) | 1534 | err = fb_find_mode(&info->var, info, mode_option, |
1485 | info->var = tdfx_var; | 1535 | specs->modedb, specs->modedb_len, |
1536 | NULL, info->var.bits_per_pixel); | ||
1537 | if (!err || err == 4) | ||
1538 | info->var = tdfx_var; | ||
1539 | } | ||
1540 | |||
1541 | if (found) { | ||
1542 | fb_destroy_modedb(specs->modedb); | ||
1543 | specs->modedb = NULL; | ||
1544 | } | ||
1486 | 1545 | ||
1487 | /* maximize virtual vertical length */ | 1546 | /* maximize virtual vertical length */ |
1488 | lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); | 1547 | lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); |