Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / drivers / video / modedb.c
index 47516c4..ff54546 100644 (file)
@@ -182,6 +182,10 @@ static const struct fb_videomode modedb[] = {
        /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
        NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
        FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+       /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */
+       NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
     }, {
        /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
        NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
@@ -251,6 +255,14 @@ static const struct fb_videomode modedb[] = {
        NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
        FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
        FB_VMODE_NONINTERLACED
+    }, {
+       /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
+       NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+       /* 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
     },
 };
 
@@ -492,7 +504,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
     /* Set up defaults */
     if (!db) {
        db = modedb;
-       dbsize = sizeof(modedb)/sizeof(*modedb);
+       dbsize = ARRAY_SIZE(modedb);
     }
     if (!default_mode)
        default_mode = &modedb[DEFAULT_MODEDB_INDEX];
@@ -676,6 +688,8 @@ void fb_var_to_videomode(struct fb_videomode *mode,
        mode->sync = var->sync;
        mode->vmode = var->vmode & FB_VMODE_MASK;
        mode->flag = FB_MODE_IS_FROM_VAR;
+       mode->refresh = 0;
+
        if (!var->pixclock)
                return;
 
@@ -777,47 +791,48 @@ struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
                        if (diff > d) {
                                diff = d;
                                best = mode;
-                       } else if (diff == d && mode->refresh > best->refresh)
-                           best = mode;
+                       } else if (diff == d && best &&
+                                  mode->refresh > best->refresh)
+                               best = mode;
                }
        }
        return best;
 }
 
 /**
- * fb_find_nearest_mode - find mode closest video mode
+ * fb_find_nearest_mode - find closest videomode
  *
- * @var: pointer to struct fb_var_screeninfo
+ * @mode: pointer to struct fb_videomode
  * @head: pointer to modelist
  *
  * Finds best matching videomode, smaller or greater in dimension.
  * If more than 1 videomode is found, will return the videomode with
- * the closest refresh rate
+ * the closest refresh rate.
  */
-struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var,
+struct fb_videomode *fb_find_nearest_mode(struct fb_videomode *mode,
                                          struct list_head *head)
 {
        struct list_head *pos;
        struct fb_modelist *modelist;
-       struct fb_videomode *mode, *best = NULL;
+       struct fb_videomode *cmode, *best = NULL;
        u32 diff = -1, diff_refresh = -1;
 
        list_for_each(pos, head) {
                u32 d;
 
                modelist = list_entry(pos, struct fb_modelist, list);
-               mode = &modelist->mode;
+               cmode = &modelist->mode;
 
-               d = abs(mode->xres - var->xres) +
-                       abs(mode->yres - var->yres);
+               d = abs(cmode->xres - mode->xres) +
+                       abs(cmode->yres - mode->yres);
                if (diff > d) {
                        diff = d;
-                       best = mode;
+                       best = cmode;
                } else if (diff == d) {
-                       d = abs(mode->refresh - best->refresh);
+                       d = abs(cmode->refresh - mode->refresh);
                        if (diff_refresh > d) {
                                diff_refresh = d;
-                               best = mode;
+                               best = cmode;
                        }
                }
        }
@@ -942,12 +957,70 @@ void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
        }
 }
 
+struct fb_videomode *fb_find_best_display(struct fb_monspecs *specs,
+                                         struct list_head *head)
+{
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL;
+       int first = 0;
+
+       if (!head->prev || !head->next || list_empty(head))
+               goto finished;
+
+       /* get the first detailed mode and the very first mode */
+       list_for_each(pos, head) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               m = &modelist->mode;
+
+               if (!first) {
+                       m1 = m;
+                       first = 1;
+               }
+
+               if (m->flag & FB_MODE_IS_FIRST) {
+                       md = m;
+                       break;
+               }
+       }
+
+       /* first detailed timing is preferred */
+       if (specs->misc & FB_MISC_1ST_DETAIL) {
+               best = md;
+               goto finished;
+       }
+
+       /* find best mode based on display width and height */
+       if (specs->max_x && specs->max_y) {
+               struct fb_var_screeninfo var;
+
+               memset(&var, 0, sizeof(struct fb_var_screeninfo));
+               var.xres = (specs->max_x * 7200)/254;
+               var.yres = (specs->max_y * 7200)/254;
+               m = fb_find_best_mode(&var, head);
+               if (m) {
+                       best = m;
+                       goto finished;
+               }
+       }
+
+       /* use first detailed mode */
+       if (md) {
+               best = md;
+               goto finished;
+       }
+
+       /* last resort, use the very first mode */
+       best = m1;
+finished:
+       return best;
+}
+EXPORT_SYMBOL(fb_find_best_display);
+
 EXPORT_SYMBOL(fb_videomode_to_var);
 EXPORT_SYMBOL(fb_var_to_videomode);
 EXPORT_SYMBOL(fb_mode_is_equal);
 EXPORT_SYMBOL(fb_add_videomode);
-EXPORT_SYMBOL(fb_delete_videomode);
-EXPORT_SYMBOL(fb_destroy_modelist);
 EXPORT_SYMBOL(fb_match_mode);
 EXPORT_SYMBOL(fb_find_best_mode);
 EXPORT_SYMBOL(fb_find_nearest_mode);