Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
   1/*
   2 *  linux/drivers/video/modedb.c -- Standard video mode database management
   3 *
   4 *	Copyright (C) 1999 Geert Uytterhoeven
   5 *
   6 *	2001 - Documented with DocBook
   7 *	- Brad Douglas <brad@neruo.com>
   8 *
   9 *  This file is subject to the terms and conditions of the GNU General Public
  10 *  License. See the file COPYING in the main directory of this archive for
  11 *  more details.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/slab.h>
  16#include <linux/fb.h>
  17#include <linux/kernel.h>
  18
  19#undef DEBUG
  20
  21#define name_matches(v, s, l) \
  22    ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
  23#define res_matches(v, x, y) \
  24    ((v).xres == (x) && (v).yres == (y))
  25
  26#ifdef DEBUG
  27#define DPRINTK(fmt, args...)	printk("modedb %s: " fmt, __func__ , ## args)
  28#else
  29#define DPRINTK(fmt, args...)
  30#endif
  31
  32const char *fb_mode_option;
  33EXPORT_SYMBOL_GPL(fb_mode_option);
  34
  35/*
  36 *  Standard video mode definitions (taken from XFree86)
  37 */
  38
  39static const struct fb_videomode modedb[] = {
  40
  41	/* 640x400 @ 70 Hz, 31.5 kHz hsync */
  42	{ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0,
  43		FB_VMODE_NONINTERLACED },
  44
  45	/* 640x480 @ 60 Hz, 31.5 kHz hsync */
  46	{ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,	0,
  47		FB_VMODE_NONINTERLACED },
  48
  49	/* 800x600 @ 56 Hz, 35.15 kHz hsync */
  50	{ NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,	0,
  51		FB_VMODE_NONINTERLACED },
  52
  53	/* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
  54	{ NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0,
  55		FB_VMODE_INTERLACED },
  56
  57	/* 640x400 @ 85 Hz, 37.86 kHz hsync */
  58	{ NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
  59		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
  60
  61	/* 640x480 @ 72 Hz, 36.5 kHz hsync */
  62	{ NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0,
  63		FB_VMODE_NONINTERLACED },
  64
  65	/* 640x480 @ 75 Hz, 37.50 kHz hsync */
  66	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,	0,
  67		FB_VMODE_NONINTERLACED },
  68
  69	/* 800x600 @ 60 Hz, 37.8 kHz hsync */
  70	{ NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
  71		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  72		FB_VMODE_NONINTERLACED },
  73
  74	/* 640x480 @ 85 Hz, 43.27 kHz hsync */
  75	{ NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0,
  76		FB_VMODE_NONINTERLACED },
  77
  78	/* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
  79	{ NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0,
  80		FB_VMODE_INTERLACED },
  81	/* 800x600 @ 72 Hz, 48.0 kHz hsync */
  82	{ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
  83		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  84		FB_VMODE_NONINTERLACED },
  85
  86	/* 1024x768 @ 60 Hz, 48.4 kHz hsync */
  87	{ NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0,
  88		FB_VMODE_NONINTERLACED },
  89
  90	/* 640x480 @ 100 Hz, 53.01 kHz hsync */
  91	{ NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,	0,
  92		FB_VMODE_NONINTERLACED },
  93
  94	/* 1152x864 @ 60 Hz, 53.5 kHz hsync */
  95	{ NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0,
  96		FB_VMODE_NONINTERLACED },
  97
  98	/* 800x600 @ 85 Hz, 55.84 kHz hsync */
  99	{ NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0,
 100		FB_VMODE_NONINTERLACED },
 101
 102	/* 1024x768 @ 70 Hz, 56.5 kHz hsync */
 103	{ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
 104		FB_VMODE_NONINTERLACED },
 105
 106	/* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
 107	{ NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12,	0,
 108		FB_VMODE_INTERLACED },
 109
 110	/* 800x600 @ 100 Hz, 64.02 kHz hsync */
 111	{ NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0,
 112		FB_VMODE_NONINTERLACED },
 113
 114	/* 1024x768 @ 76 Hz, 62.5 kHz hsync */
 115	{ NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0,
 116		FB_VMODE_NONINTERLACED },
 117
 118	/* 1152x864 @ 70 Hz, 62.4 kHz hsync */
 119	{ NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0,
 120		FB_VMODE_NONINTERLACED },
 121
 122	/* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
 123	{ NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0,
 124		FB_VMODE_NONINTERLACED },
 125
 126	/* 1400x1050 @ 60Hz, 63.9 kHz hsync */
 127	{ NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0,
 128		FB_VMODE_NONINTERLACED },
 129
 130	/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
 131	{ NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13,
 132		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 133		FB_VMODE_NONINTERLACED },
 134
 135	/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
 136	{ NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
 137		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 138		FB_VMODE_NONINTERLACED },
 139
 140	/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
 141	{ NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0,
 142		FB_VMODE_NONINTERLACED },
 143
 144	/* 1152x864 @ 78 Hz, 70.8 kHz hsync */
 145	{ NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0,
 146		FB_VMODE_NONINTERLACED },
 147
 148	/* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
 149	{ NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0,
 150		FB_VMODE_NONINTERLACED },
 151
 152	/* 1600x1200 @ 60Hz, 75.00 kHz hsync */
 153	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
 154		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 155		FB_VMODE_NONINTERLACED },
 156
 157	/* 1152x864 @ 84 Hz, 76.0 kHz hsync */
 158	{ NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0,
 159		FB_VMODE_NONINTERLACED },
 160
 161	/* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
 162	{ NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0,
 163		FB_VMODE_NONINTERLACED },
 164
 165	/* 1024x768 @ 100Hz, 80.21 kHz hsync */
 166	{ NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0,
 167		FB_VMODE_NONINTERLACED },
 168
 169	/* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
 170	{ NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0,
 171		FB_VMODE_NONINTERLACED },
 172
 173	/* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
 174	{ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0,
 175		FB_VMODE_NONINTERLACED },
 176
 177	/* 1152x864 @ 100 Hz, 89.62 kHz hsync */
 178	{ NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0,
 179		FB_VMODE_NONINTERLACED },
 180
 181	/* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
 182	{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
 183		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 184		FB_VMODE_NONINTERLACED },
 185
 186	/* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
 187	{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
 188		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 189		FB_VMODE_NONINTERLACED },
 190
 191	/* 1680x1050 @ 60 Hz, 65.191 kHz hsync */
 192	{ NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
 193		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 194		FB_VMODE_NONINTERLACED },
 195
 196	/* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
 197	{ NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
 198		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 199		FB_VMODE_NONINTERLACED },
 200
 201	/* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
 202	{ NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0,
 203		FB_VMODE_NONINTERLACED },
 204
 205	/* 1800x1440 @ 64Hz, 96.15 kHz hsync  */
 206	{ NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
 207		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 208		FB_VMODE_NONINTERLACED },
 209
 210	/* 1800x1440 @ 70Hz, 104.52 kHz hsync  */
 211	{ NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
 212		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 213		FB_VMODE_NONINTERLACED },
 214
 215	/* 512x384 @ 78 Hz, 31.50 kHz hsync */
 216	{ NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0,
 217		FB_VMODE_NONINTERLACED },
 218
 219	/* 512x384 @ 85 Hz, 34.38 kHz hsync */
 220	{ NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0,
 221		FB_VMODE_NONINTERLACED },
 222
 223	/* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
 224	{ NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0,
 225		FB_VMODE_DOUBLE },
 226
 227	/* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
 228	{ NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0,
 229		FB_VMODE_DOUBLE },
 230
 231	/* 320x240 @ 72 Hz, 36.5 kHz hsync */
 232	{ NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0,
 233		FB_VMODE_DOUBLE },
 234
 235	/* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
 236	{ NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0,
 237		FB_VMODE_DOUBLE },
 238
 239	/* 400x300 @ 60 Hz, 37.8 kHz hsync */
 240	{ NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0,
 241		FB_VMODE_DOUBLE },
 242
 243	/* 400x300 @ 72 Hz, 48.0 kHz hsync */
 244	{ NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,	0,
 245		FB_VMODE_DOUBLE },
 246
 247	/* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
 248	{ NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0,
 249		FB_VMODE_DOUBLE },
 250
 251	/* 480x300 @ 60 Hz, 37.8 kHz hsync */
 252	{ NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0,
 253		FB_VMODE_DOUBLE },
 254
 255	/* 480x300 @ 63 Hz, 39.6 kHz hsync */
 256	{ NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0,
 257		FB_VMODE_DOUBLE },
 258
 259	/* 480x300 @ 72 Hz, 48.0 kHz hsync */
 260	{ NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0,
 261		FB_VMODE_DOUBLE },
 262
 263	/* 1920x1200 @ 60 Hz, 74.5 Khz hsync */
 264	{ NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
 265		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 266		FB_VMODE_NONINTERLACED },
 267
 268	/* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
 269	{ NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6,
 270		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 271		FB_VMODE_NONINTERLACED },
 272
 273	/* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
 274	{ NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0,
 275		FB_VMODE_NONINTERLACED },
 276
 277	/* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
 278	{ NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0,
 279		FB_VMODE_NONINTERLACED },
 280
 281	/* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
 282	{ NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0,
 283		FB_VMODE_INTERLACED },
 284
 285	/* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
 286	{ NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0,
 287		FB_VMODE_INTERLACED },
 288
 289	/* 864x480 @ 60 Hz, 35.15 kHz hsync */
 290	{ NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0,
 291		0, FB_VMODE_NONINTERLACED },
 292};
 293
 294#ifdef CONFIG_FB_MODE_HELPERS
 295const struct fb_videomode cea_modes[64] = {
 296	/* #1: 640x480p@59.94/60Hz */
 297	[1] = {
 298		NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
 299		FB_VMODE_NONINTERLACED, 0,
 300	},
 301	/* #3: 720x480p@59.94/60Hz */
 302	[3] = {
 303		NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
 304		FB_VMODE_NONINTERLACED, 0,
 305	},
 306	/* #5: 1920x1080i@59.94/60Hz */
 307	[5] = {
 308		NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
 309		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 310		FB_VMODE_INTERLACED, 0,
 311	},
 312	/* #7: 720(1440)x480iH@59.94/60Hz */
 313	[7] = {
 314		NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
 315		FB_VMODE_INTERLACED, 0,
 316	},
 317	/* #9: 720(1440)x240pH@59.94/60Hz */
 318	[9] = {
 319		NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
 320		FB_VMODE_NONINTERLACED, 0,
 321	},
 322	/* #18: 720x576pH@50Hz */
 323	[18] = {
 324		NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
 325		FB_VMODE_NONINTERLACED, 0,
 326	},
 327	/* #19: 1280x720p@50Hz */
 328	[19] = {
 329		NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
 330		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 331		FB_VMODE_NONINTERLACED, 0,
 332	},
 333	/* #20: 1920x1080i@50Hz */
 334	[20] = {
 335		NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
 336		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 337		FB_VMODE_INTERLACED, 0,
 338	},
 339	/* #32: 1920x1080p@23.98/24Hz */
 340	[32] = {
 341		NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
 342		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 343		FB_VMODE_NONINTERLACED, 0,
 344	},
 345	/* #35: (2880)x480p4x@59.94/60Hz */
 346	[35] = {
 347		NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0,
 348		FB_VMODE_NONINTERLACED, 0,
 349	},
 350};
 351
 352const struct fb_videomode vesa_modes[] = {
 353	/* 0 640x350-85 VESA */
 354	{ NULL, 85, 640, 350, 31746,  96, 32, 60, 32, 64, 3,
 355	  FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
 356	/* 1 640x400-85 VESA */
 357	{ NULL, 85, 640, 400, 31746,  96, 32, 41, 01, 64, 3,
 358	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 359	/* 2 720x400-85 VESA */
 360	{ NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
 361	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 362	/* 3 640x480-60 VESA */
 363	{ NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
 364	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 365	/* 4 640x480-72 VESA */
 366	{ NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
 367	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 368	/* 5 640x480-75 VESA */
 369	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
 370	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 371	/* 6 640x480-85 VESA */
 372	{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
 373	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 374	/* 7 800x600-56 VESA */
 375	{ NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
 376	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 377	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 378	/* 8 800x600-60 VESA */
 379	{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
 380	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 381	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 382	/* 9 800x600-72 VESA */
 383	{ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
 384	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 385	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 386	/* 10 800x600-75 VESA */
 387	{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
 388	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 389	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 390	/* 11 800x600-85 VESA */
 391	{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
 392	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 393	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 394        /* 12 1024x768i-43 VESA */
 395	{ NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
 396	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 397	  FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
 398	/* 13 1024x768-60 VESA */
 399	{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
 400	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 401	/* 14 1024x768-70 VESA */
 402	{ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
 403	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 404	/* 15 1024x768-75 VESA */
 405	{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
 406	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 407	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 408	/* 16 1024x768-85 VESA */
 409	{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
 410	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 411	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 412	/* 17 1152x864-75 VESA */
 413	{ NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
 414	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 415	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 416	/* 18 1280x960-60 VESA */
 417	{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
 418	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 419	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 420	/* 19 1280x960-85 VESA */
 421	{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
 422	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 423	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 424	/* 20 1280x1024-60 VESA */
 425	{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
 426	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 427	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 428	/* 21 1280x1024-75 VESA */
 429	{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
 430	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 431	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 432	/* 22 1280x1024-85 VESA */
 433	{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
 434	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 435	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 436	/* 23 1600x1200-60 VESA */
 437	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
 438	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 439	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 440	/* 24 1600x1200-65 VESA */
 441	{ NULL, 65, 1600, 1200, 5698, 304,  64, 46, 1, 192, 3,
 442	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 443	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 444	/* 25 1600x1200-70 VESA */
 445	{ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
 446	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 447	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 448	/* 26 1600x1200-75 VESA */
 449	{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
 450	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 451	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 452	/* 27 1600x1200-85 VESA */
 453	{ NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
 454	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 455	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 456	/* 28 1792x1344-60 VESA */
 457	{ NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
 458	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 459	/* 29 1792x1344-75 VESA */
 460	{ NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
 461	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 462	/* 30 1856x1392-60 VESA */
 463	{ NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
 464	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 465	/* 31 1856x1392-75 VESA */
 466	{ NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
 467	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 468	/* 32 1920x1440-60 VESA */
 469	{ NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
 470	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 471	/* 33 1920x1440-75 VESA */
 472	{ NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
 473	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 474};
 475EXPORT_SYMBOL(vesa_modes);
 476#endif /* CONFIG_FB_MODE_HELPERS */
 477
 478/**
 479 *	fb_try_mode - test a video mode
 480 *	@var: frame buffer user defined part of display
 481 *	@info: frame buffer info structure
 482 *	@mode: frame buffer video mode structure
 483 *	@bpp: color depth in bits per pixel
 484 *
 485 *	Tries a video mode to test it's validity for device @info.
 486 *
 487 *	Returns 1 on success.
 488 *
 489 */
 490
 491static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
 492		       const struct fb_videomode *mode, unsigned int bpp)
 493{
 494    int err = 0;
 495
 496    DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname",
 497	    mode->xres, mode->yres, bpp, mode->refresh);
 498    var->xres = mode->xres;
 499    var->yres = mode->yres;
 500    var->xres_virtual = mode->xres;
 501    var->yres_virtual = mode->yres;
 502    var->xoffset = 0;
 503    var->yoffset = 0;
 504    var->bits_per_pixel = bpp;
 505    var->activate |= FB_ACTIVATE_TEST;
 506    var->pixclock = mode->pixclock;
 507    var->left_margin = mode->left_margin;
 508    var->right_margin = mode->right_margin;
 509    var->upper_margin = mode->upper_margin;
 510    var->lower_margin = mode->lower_margin;
 511    var->hsync_len = mode->hsync_len;
 512    var->vsync_len = mode->vsync_len;
 513    var->sync = mode->sync;
 514    var->vmode = mode->vmode;
 515    if (info->fbops->fb_check_var)
 516    	err = info->fbops->fb_check_var(var, info);
 517    var->activate &= ~FB_ACTIVATE_TEST;
 518    return err;
 519}
 520
 521/**
 522 *	fb_find_mode - finds a valid video mode
 523 *	@var: frame buffer user defined part of display
 524 *	@info: frame buffer info structure
 525 *	@mode_option: string video mode to find
 526 *	@db: video mode database
 527 *	@dbsize: size of @db
 528 *	@default_mode: default video mode to fall back to
 529 *	@default_bpp: default color depth in bits per pixel
 530 *
 531 *	Finds a suitable video mode, starting with the specified mode
 532 *	in @mode_option with fallback to @default_mode.  If
 533 *	@default_mode fails, all modes in the video mode database will
 534 *	be tried.
 535 *
 536 *	Valid mode specifiers for @mode_option:
 537 *
 538 *	<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
 539 *	<name>[-<bpp>][@<refresh>]
 540 *
 541 *	with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
 542 *	<name> a string.
 543 *
 544 *      If 'M' is present after yres (and before refresh/bpp if present),
 545 *      the function will compute the timings using VESA(tm) Coordinated
 546 *      Video Timings (CVT).  If 'R' is present after 'M', will compute with
 547 *      reduced blanking (for flatpanels).  If 'i' is present, compute
 548 *      interlaced mode.  If 'm' is present, add margins equal to 1.8%
 549 *      of xres rounded down to 8 pixels, and 1.8% of yres. The char
 550 *      'i' and 'm' must be after 'M' and 'R'. Example:
 551 *
 552 *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
 553 *
 554 *	NOTE: The passed struct @var is _not_ cleared!  This allows you
 555 *	to supply values for e.g. the grayscale and accel_flags fields.
 556 *
 557 *	Returns zero for failure, 1 if using specified @mode_option,
 558 *	2 if using specified @mode_option with an ignored refresh rate,
 559 *	3 if default mode is used, 4 if fall back to any valid mode.
 560 *
 561 */
 562
 563int fb_find_mode(struct fb_var_screeninfo *var,
 564		 struct fb_info *info, const char *mode_option,
 565		 const struct fb_videomode *db, unsigned int dbsize,
 566		 const struct fb_videomode *default_mode,
 567		 unsigned int default_bpp)
 568{
 569    int i;
 570
 571    /* Set up defaults */
 572    if (!db) {
 573	db = modedb;
 574	dbsize = ARRAY_SIZE(modedb);
 575    }
 576
 577    if (!default_mode)
 578	default_mode = &db[0];
 579
 580    if (!default_bpp)
 581	default_bpp = 8;
 582
 583    /* Did the user specify a video mode? */
 584    if (!mode_option)
 585	mode_option = fb_mode_option;
 586    if (mode_option) {
 587	const char *name = mode_option;
 588	unsigned int namelen = strlen(name);
 589	int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
 590	unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
 591	int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
 592	u32 best, diff, tdiff;
 593
 594	for (i = namelen-1; i >= 0; i--) {
 595	    switch (name[i]) {
 596		case '@':
 597		    namelen = i;
 598		    if (!refresh_specified && !bpp_specified &&
 599			!yres_specified) {
 600			refresh = simple_strtol(&name[i+1], NULL, 10);
 601			refresh_specified = 1;
 602			if (cvt || rb)
 603			    cvt = 0;
 604		    } else
 605			goto done;
 606		    break;
 607		case '-':
 608		    namelen = i;
 609		    if (!bpp_specified && !yres_specified) {
 610			bpp = simple_strtol(&name[i+1], NULL, 10);
 611			bpp_specified = 1;
 612			if (cvt || rb)
 613			    cvt = 0;
 614		    } else
 615			goto done;
 616		    break;
 617		case 'x':
 618		    if (!yres_specified) {
 619			yres = simple_strtol(&name[i+1], NULL, 10);
 620			yres_specified = 1;
 621		    } else
 622			goto done;
 623		    break;
 624		case '0' ... '9':
 625		    break;
 626		case 'M':
 627		    if (!yres_specified)
 628			cvt = 1;
 629		    break;
 630		case 'R':
 631		    if (!cvt)
 632			rb = 1;
 633		    break;
 634		case 'm':
 635		    if (!cvt)
 636			margins = 1;
 637		    break;
 638		case 'i':
 639		    if (!cvt)
 640			interlace = 1;
 641		    break;
 642		default:
 643		    goto done;
 644	    }
 645	}
 646	if (i < 0 && yres_specified) {
 647	    xres = simple_strtol(name, NULL, 10);
 648	    res_specified = 1;
 649	}
 650done:
 651	if (cvt) {
 652	    struct fb_videomode cvt_mode;
 653	    int ret;
 654
 655	    DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
 656		    (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
 657		    "", (margins) ? " with margins" : "", (interlace) ?
 658		    " interlaced" : "");
 659
 660	    memset(&cvt_mode, 0, sizeof(cvt_mode));
 661	    cvt_mode.xres = xres;
 662	    cvt_mode.yres = yres;
 663	    cvt_mode.refresh = (refresh) ? refresh : 60;
 664
 665	    if (interlace)
 666		cvt_mode.vmode |= FB_VMODE_INTERLACED;
 667	    else
 668		cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
 669
 670	    ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
 671
 672	    if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
 673		DPRINTK("modedb CVT: CVT mode ok\n");
 674		return 1;
 675	    }
 676
 677	    DPRINTK("CVT mode invalid, getting mode from database\n");
 678	}
 679
 680	DPRINTK("Trying specified video mode%s %ix%i\n",
 681	    refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
 682
 683	if (!refresh_specified) {
 684		/*
 685		 * If the caller has provided a custom mode database and a
 686		 * valid monspecs structure, we look for the mode with the
 687		 * highest refresh rate.  Otherwise we play it safe it and
 688		 * try to find a mode with a refresh rate closest to the
 689		 * standard 60 Hz.
 690		 */
 691		if (db != modedb &&
 692		    info->monspecs.vfmin && info->monspecs.vfmax &&
 693		    info->monspecs.hfmin && info->monspecs.hfmax &&
 694		    info->monspecs.dclkmax) {
 695			refresh = 1000;
 696		} else {
 697			refresh = 60;
 698		}
 699	}
 700
 701	diff = -1;
 702	best = -1;
 703	for (i = 0; i < dbsize; i++) {
 704		if ((name_matches(db[i], name, namelen) ||
 705		    (res_specified && res_matches(db[i], xres, yres))) &&
 706		    !fb_try_mode(var, info, &db[i], bpp)) {
 707			if (refresh_specified && db[i].refresh == refresh) {
 708				return 1;
 709			} else {
 710				if (abs(db[i].refresh - refresh) < diff) {
 711					diff = abs(db[i].refresh - refresh);
 712					best = i;
 713				}
 714			}
 715		}
 716	}
 717	if (best != -1) {
 718		fb_try_mode(var, info, &db[best], bpp);
 719		return (refresh_specified) ? 2 : 1;
 720	}
 721
 722	diff = 2 * (xres + yres);
 723	best = -1;
 724	DPRINTK("Trying best-fit modes\n");
 725	for (i = 0; i < dbsize; i++) {
 726		DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
 727		if (!fb_try_mode(var, info, &db[i], bpp)) {
 728			tdiff = abs(db[i].xres - xres) +
 729				abs(db[i].yres - yres);
 730
 731			/*
 732			 * Penalize modes with resolutions smaller
 733			 * than requested.
 734			 */
 735			if (xres > db[i].xres || yres > db[i].yres)
 736				tdiff += xres + yres;
 737
 738			if (diff > tdiff) {
 739				diff = tdiff;
 740				best = i;
 741			}
 742		}
 743	}
 744	if (best != -1) {
 745	    fb_try_mode(var, info, &db[best], bpp);
 746	    return 5;
 747	}
 748    }
 749
 750    DPRINTK("Trying default video mode\n");
 751    if (!fb_try_mode(var, info, default_mode, default_bpp))
 752	return 3;
 753
 754    DPRINTK("Trying all modes\n");
 755    for (i = 0; i < dbsize; i++)
 756	if (!fb_try_mode(var, info, &db[i], default_bpp))
 757	    return 4;
 758
 759    DPRINTK("No valid mode found\n");
 760    return 0;
 761}
 762
 763/**
 764 * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode
 765 * @mode: pointer to struct fb_videomode
 766 * @var: pointer to struct fb_var_screeninfo
 767 */
 768void fb_var_to_videomode(struct fb_videomode *mode,
 769			 const struct fb_var_screeninfo *var)
 770{
 771	u32 pixclock, hfreq, htotal, vtotal;
 772
 773	mode->name = NULL;
 774	mode->xres = var->xres;
 775	mode->yres = var->yres;
 776	mode->pixclock = var->pixclock;
 777	mode->hsync_len = var->hsync_len;
 778	mode->vsync_len = var->vsync_len;
 779	mode->left_margin = var->left_margin;
 780	mode->right_margin = var->right_margin;
 781	mode->upper_margin = var->upper_margin;
 782	mode->lower_margin = var->lower_margin;
 783	mode->sync = var->sync;
 784	mode->vmode = var->vmode & FB_VMODE_MASK;
 785	mode->flag = FB_MODE_IS_FROM_VAR;
 786	mode->refresh = 0;
 787
 788	if (!var->pixclock)
 789		return;
 790
 791	pixclock = PICOS2KHZ(var->pixclock) * 1000;
 792
 793	htotal = var->xres + var->right_margin + var->hsync_len +
 794		var->left_margin;
 795	vtotal = var->yres + var->lower_margin + var->vsync_len +
 796		var->upper_margin;
 797
 798	if (var->vmode & FB_VMODE_INTERLACED)
 799		vtotal /= 2;
 800	if (var->vmode & FB_VMODE_DOUBLE)
 801		vtotal *= 2;
 802
 803	hfreq = pixclock/htotal;
 804	mode->refresh = hfreq/vtotal;
 805}
 806
 807/**
 808 * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo
 809 * @var: pointer to struct fb_var_screeninfo
 810 * @mode: pointer to struct fb_videomode
 811 */
 812void fb_videomode_to_var(struct fb_var_screeninfo *var,
 813			 const struct fb_videomode *mode)
 814{
 815	var->xres = mode->xres;
 816	var->yres = mode->yres;
 817	var->xres_virtual = mode->xres;
 818	var->yres_virtual = mode->yres;
 819	var->xoffset = 0;
 820	var->yoffset = 0;
 821	var->pixclock = mode->pixclock;
 822	var->left_margin = mode->left_margin;
 823	var->right_margin = mode->right_margin;
 824	var->upper_margin = mode->upper_margin;
 825	var->lower_margin = mode->lower_margin;
 826	var->hsync_len = mode->hsync_len;
 827	var->vsync_len = mode->vsync_len;
 828	var->sync = mode->sync;
 829	var->vmode = mode->vmode & FB_VMODE_MASK;
 830}
 831
 832/**
 833 * fb_mode_is_equal - compare 2 videomodes
 834 * @mode1: first videomode
 835 * @mode2: second videomode
 836 *
 837 * RETURNS:
 838 * 1 if equal, 0 if not
 839 */
 840int fb_mode_is_equal(const struct fb_videomode *mode1,
 841		     const struct fb_videomode *mode2)
 842{
 843	return (mode1->xres         == mode2->xres &&
 844		mode1->yres         == mode2->yres &&
 845		mode1->pixclock     == mode2->pixclock &&
 846		mode1->hsync_len    == mode2->hsync_len &&
 847		mode1->vsync_len    == mode2->vsync_len &&
 848		mode1->left_margin  == mode2->left_margin &&
 849		mode1->right_margin == mode2->right_margin &&
 850		mode1->upper_margin == mode2->upper_margin &&
 851		mode1->lower_margin == mode2->lower_margin &&
 852		mode1->sync         == mode2->sync &&
 853		mode1->vmode        == mode2->vmode);
 854}
 855
 856/**
 857 * fb_find_best_mode - find best matching videomode
 858 * @var: pointer to struct fb_var_screeninfo
 859 * @head: pointer to struct list_head of modelist
 860 *
 861 * RETURNS:
 862 * struct fb_videomode, NULL if none found
 863 *
 864 * IMPORTANT:
 865 * This function assumes that all modelist entries in
 866 * info->modelist are valid.
 867 *
 868 * NOTES:
 869 * Finds best matching videomode which has an equal or greater dimension than
 870 * var->xres and var->yres.  If more than 1 videomode is found, will return
 871 * the videomode with the highest refresh rate
 872 */
 873const struct fb_videomode *fb_find_best_mode(const struct fb_var_screeninfo *var,
 874					     struct list_head *head)
 875{
 876	struct list_head *pos;
 877	struct fb_modelist *modelist;
 878	struct fb_videomode *mode, *best = NULL;
 879	u32 diff = -1;
 880
 881	list_for_each(pos, head) {
 882		u32 d;
 883
 884		modelist = list_entry(pos, struct fb_modelist, list);
 885		mode = &modelist->mode;
 886
 887		if (mode->xres >= var->xres && mode->yres >= var->yres) {
 888			d = (mode->xres - var->xres) +
 889				(mode->yres - var->yres);
 890			if (diff > d) {
 891				diff = d;
 892				best = mode;
 893			} else if (diff == d && best &&
 894				   mode->refresh > best->refresh)
 895				best = mode;
 896		}
 897	}
 898	return best;
 899}
 900
 901/**
 902 * fb_find_nearest_mode - find closest videomode
 903 *
 904 * @mode: pointer to struct fb_videomode
 905 * @head: pointer to modelist
 906 *
 907 * Finds best matching videomode, smaller or greater in dimension.
 908 * If more than 1 videomode is found, will return the videomode with
 909 * the closest refresh rate.
 910 */
 911const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode,
 912					        struct list_head *head)
 913{
 914	struct list_head *pos;
 915	struct fb_modelist *modelist;
 916	struct fb_videomode *cmode, *best = NULL;
 917	u32 diff = -1, diff_refresh = -1;
 918
 919	list_for_each(pos, head) {
 920		u32 d;
 921
 922		modelist = list_entry(pos, struct fb_modelist, list);
 923		cmode = &modelist->mode;
 924
 925		d = abs(cmode->xres - mode->xres) +
 926			abs(cmode->yres - mode->yres);
 927		if (diff > d) {
 928			diff = d;
 929			diff_refresh = abs(cmode->refresh - mode->refresh);
 930			best = cmode;
 931		} else if (diff == d) {
 932			d = abs(cmode->refresh - mode->refresh);
 933			if (diff_refresh > d) {
 934				diff_refresh = d;
 935				best = cmode;
 936			}
 937		}
 938	}
 939
 940	return best;
 941}
 942
 943/**
 944 * fb_match_mode - find a videomode which exactly matches the timings in var
 945 * @var: pointer to struct fb_var_screeninfo
 946 * @head: pointer to struct list_head of modelist
 947 *
 948 * RETURNS:
 949 * struct fb_videomode, NULL if none found
 950 */
 951const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var,
 952					 struct list_head *head)
 953{
 954	struct list_head *pos;
 955	struct fb_modelist *modelist;
 956	struct fb_videomode *m, mode;
 957
 958	fb_var_to_videomode(&mode, var);
 959	list_for_each(pos, head) {
 960		modelist = list_entry(pos, struct fb_modelist, list);
 961		m = &modelist->mode;
 962		if (fb_mode_is_equal(m, &mode))
 963			return m;
 964	}
 965	return NULL;
 966}
 967
 968/**
 969 * fb_add_videomode - adds videomode entry to modelist
 970 * @mode: videomode to add
 971 * @head: struct list_head of modelist
 972 *
 973 * NOTES:
 974 * Will only add unmatched mode entries
 975 */
 976int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)
 977{
 978	struct list_head *pos;
 979	struct fb_modelist *modelist;
 980	struct fb_videomode *m;
 981	int found = 0;
 982
 983	list_for_each(pos, head) {
 984		modelist = list_entry(pos, struct fb_modelist, list);
 985		m = &modelist->mode;
 986		if (fb_mode_is_equal(m, mode)) {
 987			found = 1;
 988			break;
 989		}
 990	}
 991	if (!found) {
 992		modelist = kmalloc(sizeof(struct fb_modelist),
 993						  GFP_KERNEL);
 994
 995		if (!modelist)
 996			return -ENOMEM;
 997		modelist->mode = *mode;
 998		list_add(&modelist->list, head);
 999	}
1000	return 0;
1001}
1002
1003/**
1004 * fb_delete_videomode - removed videomode entry from modelist
1005 * @mode: videomode to remove
1006 * @head: struct list_head of modelist
1007 *
1008 * NOTES:
1009 * Will remove all matching mode entries
1010 */
1011void fb_delete_videomode(const struct fb_videomode *mode,
1012			 struct list_head *head)
1013{
1014	struct list_head *pos, *n;
1015	struct fb_modelist *modelist;
1016	struct fb_videomode *m;
1017
1018	list_for_each_safe(pos, n, head) {
1019		modelist = list_entry(pos, struct fb_modelist, list);
1020		m = &modelist->mode;
1021		if (fb_mode_is_equal(m, mode)) {
1022			list_del(pos);
1023			kfree(pos);
1024		}
1025	}
1026}
1027
1028/**
1029 * fb_destroy_modelist - destroy modelist
1030 * @head: struct list_head of modelist
1031 */
1032void fb_destroy_modelist(struct list_head *head)
1033{
1034	struct list_head *pos, *n;
1035
1036	list_for_each_safe(pos, n, head) {
1037		list_del(pos);
1038		kfree(pos);
1039	}
1040}
1041EXPORT_SYMBOL_GPL(fb_destroy_modelist);
1042
1043/**
1044 * fb_videomode_to_modelist - convert mode array to mode list
1045 * @modedb: array of struct fb_videomode
1046 * @num: number of entries in array
1047 * @head: struct list_head of modelist
1048 */
1049void fb_videomode_to_modelist(const struct fb_videomode *modedb, int num,
1050			      struct list_head *head)
1051{
1052	int i;
1053
1054	INIT_LIST_HEAD(head);
1055
1056	for (i = 0; i < num; i++) {
1057		if (fb_add_videomode(&modedb[i], head))
1058			return;
1059	}
1060}
1061
1062const struct fb_videomode *fb_find_best_display(const struct fb_monspecs *specs,
1063					        struct list_head *head)
1064{
1065	struct list_head *pos;
1066	struct fb_modelist *modelist;
1067	const struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL;
1068	int first = 0;
1069
1070	if (!head->prev || !head->next || list_empty(head))
1071		goto finished;
1072
1073	/* get the first detailed mode and the very first mode */
1074	list_for_each(pos, head) {
1075		modelist = list_entry(pos, struct fb_modelist, list);
1076		m = &modelist->mode;
1077
1078		if (!first) {
1079			m1 = m;
1080			first = 1;
1081		}
1082
1083		if (m->flag & FB_MODE_IS_FIRST) {
1084 			md = m;
1085			break;
1086		}
1087	}
1088
1089	/* first detailed timing is preferred */
1090	if (specs->misc & FB_MISC_1ST_DETAIL) {
1091		best = md;
1092		goto finished;
1093	}
1094
1095	/* find best mode based on display width and height */
1096	if (specs->max_x && specs->max_y) {
1097		struct fb_var_screeninfo var;
1098
1099		memset(&var, 0, sizeof(struct fb_var_screeninfo));
1100		var.xres = (specs->max_x * 7200)/254;
1101		var.yres = (specs->max_y * 7200)/254;
1102		m = fb_find_best_mode(&var, head);
1103		if (m) {
1104			best = m;
1105			goto finished;
1106		}
1107	}
1108
1109	/* use first detailed mode */
1110	if (md) {
1111		best = md;
1112		goto finished;
1113	}
1114
1115	/* last resort, use the very first mode */
1116	best = m1;
1117finished:
1118	return best;
1119}
1120EXPORT_SYMBOL(fb_find_best_display);
1121
1122EXPORT_SYMBOL(fb_videomode_to_var);
1123EXPORT_SYMBOL(fb_var_to_videomode);
1124EXPORT_SYMBOL(fb_mode_is_equal);
1125EXPORT_SYMBOL(fb_add_videomode);
1126EXPORT_SYMBOL(fb_match_mode);
1127EXPORT_SYMBOL(fb_find_best_mode);
1128EXPORT_SYMBOL(fb_find_nearest_mode);
1129EXPORT_SYMBOL(fb_videomode_to_modelist);
1130EXPORT_SYMBOL(fb_find_mode);
1131EXPORT_SYMBOL(fb_find_mode_cvt);