|
@@ -487,6 +487,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (info->monspecs.hfmax && info->monspecs.vfmax &&
|
|
|
|
+ info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) {
|
|
|
|
+ DPRINTK("mode outside monitor's specs\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
|
|
var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
|
|
lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
|
|
lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
|
|
|
|
|
|
@@ -1355,6 +1361,23 @@ static void tdfxfb_delete_i2c_busses(struct tdfx_par *par)
|
|
i2c_del_adapter(&par->chan[1].adapter);
|
|
i2c_del_adapter(&par->chan[1].adapter);
|
|
par->chan[1].par = NULL;
|
|
par->chan[1].par = NULL;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+static int tdfxfb_probe_i2c_connector(struct tdfx_par *par,
|
|
|
|
+ struct fb_monspecs *specs)
|
|
|
|
+{
|
|
|
|
+ u8 *edid = NULL;
|
|
|
|
+
|
|
|
|
+ DPRINTK("Probe DDC Bus\n");
|
|
|
|
+ if (par->chan[0].par)
|
|
|
|
+ edid = fb_ddc_read(&par->chan[0].adapter);
|
|
|
|
+
|
|
|
|
+ if (edid) {
|
|
|
|
+ fb_edid_to_monspecs(edid, specs);
|
|
|
|
+ kfree(edid);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
#endif /* CONFIG_FB_3DFX_I2C */
|
|
#endif /* CONFIG_FB_3DFX_I2C */
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1372,6 +1395,8 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
|
|
struct tdfx_par *default_par;
|
|
struct tdfx_par *default_par;
|
|
struct fb_info *info;
|
|
struct fb_info *info;
|
|
int err, lpitch;
|
|
int err, lpitch;
|
|
|
|
+ struct fb_monspecs *specs;
|
|
|
|
+ bool found;
|
|
|
|
|
|
err = pci_enable_device(pdev);
|
|
err = pci_enable_device(pdev);
|
|
if (err) {
|
|
if (err) {
|
|
@@ -1474,15 +1499,49 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
|
|
if (hwcursor)
|
|
if (hwcursor)
|
|
info->fix.smem_len = (info->fix.smem_len - 1024) &
|
|
info->fix.smem_len = (info->fix.smem_len - 1024) &
|
|
(PAGE_MASK << 1);
|
|
(PAGE_MASK << 1);
|
|
|
|
+ specs = &info->monspecs;
|
|
|
|
+ found = false;
|
|
|
|
+ info->var.bits_per_pixel = 8;
|
|
#ifdef CONFIG_FB_3DFX_I2C
|
|
#ifdef CONFIG_FB_3DFX_I2C
|
|
tdfxfb_create_i2c_busses(info);
|
|
tdfxfb_create_i2c_busses(info);
|
|
|
|
+ err = tdfxfb_probe_i2c_connector(default_par, specs);
|
|
|
|
+
|
|
|
|
+ if (!err) {
|
|
|
|
+ if (specs->modedb == NULL)
|
|
|
|
+ DPRINTK("Unable to get Mode Database\n");
|
|
|
|
+ else {
|
|
|
|
+ const struct fb_videomode *m;
|
|
|
|
+
|
|
|
|
+ fb_videomode_to_modelist(specs->modedb,
|
|
|
|
+ specs->modedb_len,
|
|
|
|
+ &info->modelist);
|
|
|
|
+ m = fb_find_best_display(specs, &info->modelist);
|
|
|
|
+ if (m) {
|
|
|
|
+ fb_videomode_to_var(&info->var, m);
|
|
|
|
+ /* fill all other info->var's fields */
|
|
|
|
+ if (tdfxfb_check_var(&info->var, info) < 0)
|
|
|
|
+ info->var = tdfx_var;
|
|
|
|
+ else
|
|
|
|
+ found = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
#endif
|
|
#endif
|
|
- if (!mode_option)
|
|
|
|
|
|
+ if (!mode_option && !found)
|
|
mode_option = "640x480@60";
|
|
mode_option = "640x480@60";
|
|
|
|
|
|
- err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
|
|
|
|
- if (!err || err == 4)
|
|
|
|
- info->var = tdfx_var;
|
|
|
|
|
|
+ if (mode_option) {
|
|
|
|
+ err = fb_find_mode(&info->var, info, mode_option,
|
|
|
|
+ specs->modedb, specs->modedb_len,
|
|
|
|
+ NULL, info->var.bits_per_pixel);
|
|
|
|
+ if (!err || err == 4)
|
|
|
|
+ info->var = tdfx_var;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (found) {
|
|
|
|
+ fb_destroy_modedb(specs->modedb);
|
|
|
|
+ specs->modedb = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
/* maximize virtual vertical length */
|
|
/* maximize virtual vertical length */
|
|
lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
|
|
lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
|