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