Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / video / modedb.c
index f7f9c08..d3c3af5 100644 (file)
     ((v).xres == (x) && (v).yres == (y))
 
 #ifdef DEBUG
-#define DPRINTK(fmt, args...)  printk("modedb %s: " fmt, __FUNCTION__ , ## args)
+#define DPRINTK(fmt, args...)  printk("modedb %s: " fmt, __func__ , ## args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
 
-const char *global_mode_option;
+const char *fb_mode_option;
+EXPORT_SYMBOL_GPL(fb_mode_option);
 
     /*
      *  Standard video mode definitions (taken from XFree86)
@@ -259,6 +260,10 @@ static const struct fb_videomode modedb[] = {
        /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
        NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5,
        0, FB_VMODE_NONINTERLACED
+   }, {
+       /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
+       NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3,
+       0, FB_VMODE_NONINTERLACED
     },
 };
 
@@ -510,13 +515,15 @@ int fb_find_mode(struct fb_var_screeninfo *var,
        default_bpp = 8;
 
     /* Did the user specify a video mode? */
-    if (mode_option || (mode_option = global_mode_option)) {
+    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;
+       u32 best, diff, tdiff;
 
        for (i = namelen-1; i >= 0; i--) {
            switch (name[i]) {
@@ -584,6 +591,7 @@ done:
                    "", (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;
@@ -606,41 +614,66 @@ done:
        DPRINTK("Trying specified video mode%s %ix%i\n",
            refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
 
-       diff = refresh;
+       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))) {
-                       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 ((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 2;
+               return (refresh_specified) ? 2 : 1;
        }
 
-       diff = xres + yres;
+       diff = 2 * (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;
-                   }
+                       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);