Exemplo n.º 1
0
int fb_find_mode(struct fb_var_screeninfo *var,
		 struct fb_info *info, const char *mode_option,
		 const struct fb_videomode *db, unsigned int dbsize,
		 const struct fb_videomode *default_mode,
		 unsigned int default_bpp)
{
    int i;

    /* Set up defaults */
    if (!db) {
	db = modedb;
	dbsize = ARRAY_SIZE(modedb);
    }

    if (!default_mode)
	default_mode = &db[0];

    if (!default_bpp)
	default_bpp = 8;

    /* Did the user specify a video mode? */
    if (!mode_option)
	mode_option = fb_mode_option;
    if (mode_option) {
	const char *name = mode_option;
	unsigned int namelen = strlen(name);
	int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
	unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
	int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
	u32 best, diff, tdiff;

	for (i = namelen-1; i >= 0; i--) {
	    switch (name[i]) {
		case '@':
		    namelen = i;
		    if (!refresh_specified && !bpp_specified &&
			!yres_specified) {
			refresh = simple_strtol(&name[i+1], NULL, 10);
			refresh_specified = 1;
			if (cvt || rb)
			    cvt = 0;
		    } else
			goto done;
		    break;
		case '-':
		    namelen = i;
		    if (!bpp_specified && !yres_specified) {
			bpp = simple_strtol(&name[i+1], NULL, 10);
			bpp_specified = 1;
			if (cvt || rb)
			    cvt = 0;
		    } else
			goto done;
		    break;
		case 'x':
		    if (!yres_specified) {
			yres = simple_strtol(&name[i+1], NULL, 10);
			yres_specified = 1;
		    } else
			goto done;
		    break;
		case '0' ... '9':
		    break;
		case 'M':
		    if (!yres_specified)
			cvt = 1;
		    break;
		case 'R':
		    if (!cvt)
			rb = 1;
		    break;
		case 'm':
		    if (!cvt)
			margins = 1;
		    break;
		case 'i':
		    if (!cvt)
			interlace = 1;
		    break;
		default:
		    goto done;
	    }
	}
	if (i < 0 && yres_specified) {
	    xres = simple_strtol(name, NULL, 10);
	    res_specified = 1;
	}
done:
	if (cvt) {
	    struct fb_videomode cvt_mode;
	    int ret;

	    DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
		    (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
		    "", (margins) ? " with margins" : "", (interlace) ?
		    " interlaced" : "");

	    memset(&cvt_mode, 0, sizeof(cvt_mode));
	    cvt_mode.xres = xres;
	    cvt_mode.yres = yres;
	    cvt_mode.refresh = (refresh) ? refresh : 60;

	    if (interlace)
		cvt_mode.vmode |= FB_VMODE_INTERLACED;
	    else
		cvt_mode.vmode &= ~FB_VMODE_INTERLACED;

	    ret = fb_find_mode_cvt(&cvt_mode, margins, rb);

	    if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
		DPRINTK("modedb CVT: CVT mode ok\n");
		return 1;
	    }

	    DPRINTK("CVT mode invalid, getting mode from database\n");
	}

	DPRINTK("Trying specified video mode%s %ix%i\n",
	    refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);

	if (!refresh_specified) {
		/*
		 * If the caller has provided a custom mode database and a
		 * valid monspecs structure, we look for the mode with the
		 * highest refresh rate.  Otherwise we play it safe it and
		 * try to find a mode with a refresh rate closest to the
		 * standard 60 Hz.
		 */
		if (db != modedb &&
		    info->monspecs.vfmin && info->monspecs.vfmax &&
		    info->monspecs.hfmin && info->monspecs.hfmax &&
		    info->monspecs.dclkmax) {
			refresh = 1000;
		} else {
			refresh = 60;
		}
	}

	diff = -1;
	best = -1;
	for (i = 0; i < dbsize; i++) {
		if ((name_matches(db[i], name, namelen) ||
		    (res_specified && res_matches(db[i], xres, yres))) &&
		    !fb_try_mode(var, info, &db[i], bpp)) {
			if (refresh_specified && db[i].refresh == refresh) {
				return 1;
			} else {
				if (abs(db[i].refresh - refresh) < diff) {
					diff = abs(db[i].refresh - refresh);
					best = i;
				}
			}
		}
	}
	if (best != -1) {
		fb_try_mode(var, info, &db[best], bpp);
		return (refresh_specified) ? 2 : 1;
	}

	diff = 2 * (xres + yres);
	best = -1;
	DPRINTK("Trying best-fit modes\n");
	for (i = 0; i < dbsize; i++) {
		DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
		if (!fb_try_mode(var, info, &db[i], bpp)) {
			tdiff = abs(db[i].xres - xres) +
				abs(db[i].yres - yres);

			/*
			 * Penalize modes with resolutions smaller
			 * than requested.
			 */
			if (xres > db[i].xres || yres > db[i].yres)
				tdiff += xres + yres;

			if (diff > tdiff) {
				diff = tdiff;
				best = i;
			}
		}
	}
	if (best != -1) {
	    fb_try_mode(var, info, &db[best], bpp);
	    return 5;
	}
    }

    DPRINTK("Trying default video mode\n");
    if (!fb_try_mode(var, info, default_mode, default_bpp))
	return 3;

    DPRINTK("Trying all modes\n");
    for (i = 0; i < dbsize; i++)
	if (!fb_try_mode(var, info, &db[i], default_bpp))
	    return 4;

    DPRINTK("No valid mode found\n");
    return 0;
}
Exemplo n.º 2
0
int fb_find_mode(struct fb_var_screeninfo *var,
		 struct fb_info *info, const char *mode_option,
		 const struct fb_videomode *db, unsigned int dbsize,
		 const struct fb_videomode *default_mode,
		 unsigned int default_bpp)
{
    int i;

    /* Set up defaults */
    if (!db) {
	db = modedb;
	dbsize = ARRAY_SIZE(modedb);
    }

    if (!default_mode)
	default_mode = &db[0];

    if (!default_bpp)
	default_bpp = 8;

    /* Did the user specify a video mode? */
    if (mode_option || (mode_option = global_mode_option)) {
	const char *name = mode_option;
	unsigned int namelen = strlen(name);
	int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
	unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
	int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
	u32 best, diff;

	for (i = namelen-1; i >= 0; i--) {
	    switch (name[i]) {
		case '@':
		    namelen = i;
		    if (!refresh_specified && !bpp_specified &&
			!yres_specified) {
			refresh = my_atoi(&name[i+1]);
			refresh_specified = 1;
			if (cvt || rb)
			    cvt = 0;
		    } else
			goto done;
		    break;
		case '-':
		    namelen = i;
		    if (!bpp_specified && !yres_specified) {
			bpp = my_atoi(&name[i+1]);
			bpp_specified = 1;
			if (cvt || rb)
			    cvt = 0;
		    } else
			goto done;
		    break;
		case 'x':
		    if (!yres_specified) {
			yres = my_atoi(&name[i+1]);
			yres_specified = 1;
		    } else
			goto done;
		    break;
		case '0' ... '9':
		    break;
		case 'M':
		    if (!yres_specified)
			cvt = 1;
		    break;
		case 'R':
		    if (!cvt)
			rb = 1;
		    break;
		case 'm':
		    if (!cvt)
			margins = 1;
		    break;
		case 'i':
		    if (!cvt)
			interlace = 1;
		    break;
		default:
		    goto done;
	    }
	}
	if (i < 0 && yres_specified) {
	    xres = my_atoi(name);
	    res_specified = 1;
	}
done:
	if (cvt) {
	    struct fb_videomode cvt_mode;
	    int ret;

	    DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
		    (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
		    "", (margins) ? " with margins" : "", (interlace) ?
		    " interlaced" : "");

	    cvt_mode.xres = xres;
	    cvt_mode.yres = yres;
	    cvt_mode.refresh = (refresh) ? refresh : 60;

	    if (interlace)
		cvt_mode.vmode |= FB_VMODE_INTERLACED;
	    else
		cvt_mode.vmode &= ~FB_VMODE_INTERLACED;

	    ret = fb_find_mode_cvt(&cvt_mode, margins, rb);

	    if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
		DPRINTK("modedb CVT: CVT mode ok\n");
		return 1;
	    }

	    DPRINTK("CVT mode invalid, getting mode from database\n");
	}

	DPRINTK("Trying specified video mode%s %ix%i\n",
	    refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);

	diff = refresh;
	best = -1;
	for (i = 0; i < dbsize; i++) {
		if (name_matches(db[i], name, namelen) ||
		    (res_specified && res_matches(db[i], xres, yres))) {
			if(!fb_try_mode(var, info, &db[i], bpp)) {
				if(!refresh_specified || db[i].refresh == refresh)
					return 1;
				else {
					if(diff > abs(db[i].refresh - refresh)) {
						diff = abs(db[i].refresh - refresh);
						best = i;
					}
				}
			}
		}
	}
	if (best != -1) {
		fb_try_mode(var, info, &db[best], bpp);
		return 2;
	}

	diff = xres + yres;
	best = -1;
	DPRINTK("Trying best-fit modes\n");
	for (i = 0; i < dbsize; i++) {
	    if (xres <= db[i].xres && yres <= db[i].yres) {
		DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
		if (!fb_try_mode(var, info, &db[i], bpp)) {
		    if (diff > (db[i].xres - xres) + (db[i].yres - yres)) {
			diff = (db[i].xres - xres) + (db[i].yres - yres);
			best = i;
		    }
		}
	    }
	}
	if (best != -1) {
	    fb_try_mode(var, info, &db[best], bpp);
	    return 5;
	}
    }

    DPRINTK("Trying default video mode\n");
    if (!fb_try_mode(var, info, default_mode, default_bpp))
	return 3;

    DPRINTK("Trying all modes\n");
    for (i = 0; i < dbsize; i++)
	if (!fb_try_mode(var, info, &db[i], default_bpp))
	    return 4;

    DPRINTK("No valid mode found\n");
    return 0;
}