Showing error 1651

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/video/fbmon.c
Line in file: 963
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 07:54:05 UTC


Source:

   1/*
   2 * linux/drivers/video/fbmon.c
   3 *
   4 * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
   5 *
   6 * Credits:
   7 *
   8 * The EDID Parser is a conglomeration from the following sources:
   9 *
  10 *   1. SciTech SNAP Graphics Architecture
  11 *      Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
  12 *
  13 *   2. XFree86 4.3.0, interpret_edid.c
  14 *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
  15 *
  16 *   3. John Fremlin <vii@users.sourceforge.net> and
  17 *      Ani Joshi <ajoshi@unixbox.com>
  18 *
  19 * Generalized Timing Formula is derived from:
  20 *
  21 *      GTF Spreadsheet by Andy Morrish (1/5/97)
  22 *      available at http://www.vesa.org
  23 *
  24 * This file is subject to the terms and conditions of the GNU General Public
  25 * License.  See the file COPYING in the main directory of this archive
  26 * for more details.
  27 *
  28 */
  29#include <linux/fb.h>
  30#include <linux/module.h>
  31#include <linux/pci.h>
  32#include <video/edid.h>
  33#ifdef CONFIG_PPC_OF
  34#include <asm/prom.h>
  35#include <asm/pci-bridge.h>
  36#endif
  37#include "edid.h"
  38
  39/*
  40 * EDID parser
  41 */
  42
  43#undef DEBUG  /* define this for verbose EDID parsing output */
  44
  45#ifdef DEBUG
  46#define DPRINTK(fmt, args...) printk(fmt,## args)
  47#else
  48#define DPRINTK(fmt, args...)
  49#endif
  50
  51#define FBMON_FIX_HEADER  1
  52#define FBMON_FIX_INPUT   2
  53#define FBMON_FIX_TIMINGS 3
  54
  55#ifdef CONFIG_FB_MODE_HELPERS
  56struct broken_edid {
  57        u8  manufacturer[4];
  58        u32 model;
  59        u32 fix;
  60};
  61
  62static const struct broken_edid brokendb[] = {
  63        /* DEC FR-PCXAV-YZ */
  64        {
  65                .manufacturer = "DEC",
  66                .model        = 0x073a,
  67                .fix          = FBMON_FIX_HEADER,
  68        },
  69        /* ViewSonic PF775a */
  70        {
  71                .manufacturer = "VSC",
  72                .model        = 0x5a44,
  73                .fix          = FBMON_FIX_INPUT,
  74        },
  75        /* Sharp UXGA? */
  76        {
  77                .manufacturer = "SHP",
  78                .model        = 0x138e,
  79                .fix          = FBMON_FIX_TIMINGS,
  80        },
  81};
  82
  83static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
  84        0xff, 0xff, 0xff, 0x00
  85};
  86
  87static void copy_string(unsigned char *c, unsigned char *s)
  88{
  89  int i;
  90  c = c + 5;
  91  for (i = 0; (i < 13 && *c != 0x0A); i++)
  92    *(s++) = *(c++);
  93  *s = 0;
  94  while (i-- && (*--s == 0x20)) *s = 0;
  95}
  96
  97static int edid_is_serial_block(unsigned char *block)
  98{
  99        if ((block[0] == 0x00) && (block[1] == 0x00) &&
 100            (block[2] == 0x00) && (block[3] == 0xff) &&
 101            (block[4] == 0x00))
 102                return 1;
 103        else
 104                return 0;
 105}
 106
 107static int edid_is_ascii_block(unsigned char *block)
 108{
 109        if ((block[0] == 0x00) && (block[1] == 0x00) &&
 110            (block[2] == 0x00) && (block[3] == 0xfe) &&
 111            (block[4] == 0x00))
 112                return 1;
 113        else
 114                return 0;
 115}
 116
 117static int edid_is_limits_block(unsigned char *block)
 118{
 119        if ((block[0] == 0x00) && (block[1] == 0x00) &&
 120            (block[2] == 0x00) && (block[3] == 0xfd) &&
 121            (block[4] == 0x00))
 122                return 1;
 123        else
 124                return 0;
 125}
 126
 127static int edid_is_monitor_block(unsigned char *block)
 128{
 129        if ((block[0] == 0x00) && (block[1] == 0x00) &&
 130            (block[2] == 0x00) && (block[3] == 0xfc) &&
 131            (block[4] == 0x00))
 132                return 1;
 133        else
 134                return 0;
 135}
 136
 137static int edid_is_timing_block(unsigned char *block)
 138{
 139        if ((block[0] != 0x00) || (block[1] != 0x00) ||
 140            (block[2] != 0x00) || (block[4] != 0x00))
 141                return 1;
 142        else
 143                return 0;
 144}
 145
 146static int check_edid(unsigned char *edid)
 147{
 148        unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
 149        unsigned char *b;
 150        u32 model;
 151        int i, fix = 0, ret = 0;
 152
 153        manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
 154        manufacturer[1] = ((block[0] & 0x03) << 3) +
 155                ((block[1] & 0xe0) >> 5) + '@';
 156        manufacturer[2] = (block[1] & 0x1f) + '@';
 157        manufacturer[3] = 0;
 158        model = block[2] + (block[3] << 8);
 159
 160        for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
 161                if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
 162                        brokendb[i].model == model) {
 163                        fix = brokendb[i].fix;
 164                        break;
 165                }
 166        }
 167
 168        switch (fix) {
 169        case FBMON_FIX_HEADER:
 170                for (i = 0; i < 8; i++) {
 171                        if (edid[i] != edid_v1_header[i]) {
 172                                ret = fix;
 173                                break;
 174                        }
 175                }
 176                break;
 177        case FBMON_FIX_INPUT:
 178                b = edid + EDID_STRUCT_DISPLAY;
 179                /* Only if display is GTF capable will
 180                   the input type be reset to analog */
 181                if (b[4] & 0x01 && b[0] & 0x80)
 182                        ret = fix;
 183                break;
 184        case FBMON_FIX_TIMINGS:
 185                b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 186                ret = fix;
 187
 188                for (i = 0; i < 4; i++) {
 189                        if (edid_is_limits_block(b)) {
 190                                ret = 0;
 191                                break;
 192                        }
 193
 194                        b += DETAILED_TIMING_DESCRIPTION_SIZE;
 195                }
 196
 197                break;
 198        }
 199
 200        if (ret)
 201                printk("fbmon: The EDID Block of "
 202                       "Manufacturer: %s Model: 0x%x is known to "
 203                       "be broken,\n",  manufacturer, model);
 204
 205        return ret;
 206}
 207
 208static void fix_edid(unsigned char *edid, int fix)
 209{
 210        int i;
 211        unsigned char *b, csum = 0;
 212
 213        switch (fix) {
 214        case FBMON_FIX_HEADER:
 215                printk("fbmon: trying a header reconstruct\n");
 216                memcpy(edid, edid_v1_header, 8);
 217                break;
 218        case FBMON_FIX_INPUT:
 219                printk("fbmon: trying to fix input type\n");
 220                b = edid + EDID_STRUCT_DISPLAY;
 221                b[0] &= ~0x80;
 222                edid[127] += 0x80;
 223                break;
 224        case FBMON_FIX_TIMINGS:
 225                printk("fbmon: trying to fix monitor timings\n");
 226                b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 227                for (i = 0; i < 4; i++) {
 228                        if (!(edid_is_serial_block(b) ||
 229                              edid_is_ascii_block(b) ||
 230                              edid_is_monitor_block(b) ||
 231                              edid_is_timing_block(b))) {
 232                                b[0] = 0x00;
 233                                b[1] = 0x00;
 234                                b[2] = 0x00;
 235                                b[3] = 0xfd;
 236                                b[4] = 0x00;
 237                                b[5] = 60;   /* vfmin */
 238                                b[6] = 60;   /* vfmax */
 239                                b[7] = 30;   /* hfmin */
 240                                b[8] = 75;   /* hfmax */
 241                                b[9] = 17;   /* pixclock - 170 MHz*/
 242                                b[10] = 0;   /* GTF */
 243                                break;
 244                        }
 245
 246                        b += DETAILED_TIMING_DESCRIPTION_SIZE;
 247                }
 248
 249                for (i = 0; i < EDID_LENGTH - 1; i++)
 250                        csum += edid[i];
 251
 252                edid[127] = 256 - csum;
 253                break;
 254        }
 255}
 256
 257static int edid_checksum(unsigned char *edid)
 258{
 259        unsigned char i, csum = 0, all_null = 0;
 260        int err = 0, fix = check_edid(edid);
 261
 262        if (fix)
 263                fix_edid(edid, fix);
 264
 265        for (i = 0; i < EDID_LENGTH; i++) {
 266                csum += edid[i];
 267                all_null |= edid[i];
 268        }
 269
 270        if (csum == 0x00 && all_null) {
 271                /* checksum passed, everything's good */
 272                err = 1;
 273        }
 274
 275        return err;
 276}
 277
 278static int edid_check_header(unsigned char *edid)
 279{
 280        int i, err = 1, fix = check_edid(edid);
 281
 282        if (fix)
 283                fix_edid(edid, fix);
 284
 285        for (i = 0; i < 8; i++) {
 286                if (edid[i] != edid_v1_header[i])
 287                        err = 0;
 288        }
 289
 290        return err;
 291}
 292
 293static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
 294{
 295        specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
 296        specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
 297                ((block[1] & 0xe0) >> 5) + '@';
 298        specs->manufacturer[2] = (block[1] & 0x1f) + '@';
 299        specs->manufacturer[3] = 0;
 300        specs->model = block[2] + (block[3] << 8);
 301        specs->serial = block[4] + (block[5] << 8) +
 302               (block[6] << 16) + (block[7] << 24);
 303        specs->year = block[9] + 1990;
 304        specs->week = block[8];
 305        DPRINTK("   Manufacturer: %s\n", specs->manufacturer);
 306        DPRINTK("   Model: %x\n", specs->model);
 307        DPRINTK("   Serial#: %u\n", specs->serial);
 308        DPRINTK("   Year: %u Week %u\n", specs->year, specs->week);
 309}
 310
 311static void get_dpms_capabilities(unsigned char flags,
 312                                  struct fb_monspecs *specs)
 313{
 314        specs->dpms = 0;
 315        if (flags & DPMS_ACTIVE_OFF)
 316                specs->dpms |= FB_DPMS_ACTIVE_OFF;
 317        if (flags & DPMS_SUSPEND)
 318                specs->dpms |= FB_DPMS_SUSPEND;
 319        if (flags & DPMS_STANDBY)
 320                specs->dpms |= FB_DPMS_STANDBY;
 321        DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",
 322               (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
 323               (flags & DPMS_SUSPEND)    ? "yes" : "no",
 324               (flags & DPMS_STANDBY)    ? "yes" : "no");
 325}
 326
 327static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
 328{
 329        int tmp;
 330
 331        DPRINTK("      Chroma\n");
 332        /* Chromaticity data */
 333        tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
 334        tmp *= 1000;
 335        tmp += 512;
 336        specs->chroma.redx = tmp/1024;
 337        DPRINTK("         RedX:     0.%03d ", specs->chroma.redx);
 338
 339        tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
 340        tmp *= 1000;
 341        tmp += 512;
 342        specs->chroma.redy = tmp/1024;
 343        DPRINTK("RedY:     0.%03d\n", specs->chroma.redy);
 344
 345        tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
 346        tmp *= 1000;
 347        tmp += 512;
 348        specs->chroma.greenx = tmp/1024;
 349        DPRINTK("         GreenX:   0.%03d ", specs->chroma.greenx);
 350
 351        tmp = (block[5] & 3) | (block[0xa] << 2);
 352        tmp *= 1000;
 353        tmp += 512;
 354        specs->chroma.greeny = tmp/1024;
 355        DPRINTK("GreenY:   0.%03d\n", specs->chroma.greeny);
 356
 357        tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
 358        tmp *= 1000;
 359        tmp += 512;
 360        specs->chroma.bluex = tmp/1024;
 361        DPRINTK("         BlueX:    0.%03d ", specs->chroma.bluex);
 362
 363        tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
 364        tmp *= 1000;
 365        tmp += 512;
 366        specs->chroma.bluey = tmp/1024;
 367        DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);
 368
 369        tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
 370        tmp *= 1000;
 371        tmp += 512;
 372        specs->chroma.whitex = tmp/1024;
 373        DPRINTK("         WhiteX:   0.%03d ", specs->chroma.whitex);
 374
 375        tmp = (block[6] & 3) | (block[0xe] << 2);
 376        tmp *= 1000;
 377        tmp += 512;
 378        specs->chroma.whitey = tmp/1024;
 379        DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);
 380}
 381
 382static void calc_mode_timings(int xres, int yres, int refresh,
 383                              struct fb_videomode *mode)
 384{
 385        struct fb_var_screeninfo *var;
 386
 387        var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
 388
 389        if (var) {
 390                var->xres = xres;
 391                var->yres = yres;
 392                fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
 393                            refresh, var, NULL);
 394                mode->xres = xres;
 395                mode->yres = yres;
 396                mode->pixclock = var->pixclock;
 397                mode->refresh = refresh;
 398                mode->left_margin = var->left_margin;
 399                mode->right_margin = var->right_margin;
 400                mode->upper_margin = var->upper_margin;
 401                mode->lower_margin = var->lower_margin;
 402                mode->hsync_len = var->hsync_len;
 403                mode->vsync_len = var->vsync_len;
 404                mode->vmode = 0;
 405                mode->sync = 0;
 406                kfree(var);
 407        }
 408}
 409
 410static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
 411{
 412        int num = 0;
 413        unsigned char c;
 414
 415        c = block[0];
 416        if (c&0x80) {
 417                calc_mode_timings(720, 400, 70, &mode[num]);
 418                mode[num++].flag = FB_MODE_IS_CALCULATED;
 419                DPRINTK("      720x400@70Hz\n");
 420        }
 421        if (c&0x40) {
 422                calc_mode_timings(720, 400, 88, &mode[num]);
 423                mode[num++].flag = FB_MODE_IS_CALCULATED;
 424                DPRINTK("      720x400@88Hz\n");
 425        }
 426        if (c&0x20) {
 427                mode[num++] = vesa_modes[3];
 428                DPRINTK("      640x480@60Hz\n");
 429        }
 430        if (c&0x10) {
 431                calc_mode_timings(640, 480, 67, &mode[num]);
 432                mode[num++].flag = FB_MODE_IS_CALCULATED;
 433                DPRINTK("      640x480@67Hz\n");
 434        }
 435        if (c&0x08) {
 436                mode[num++] = vesa_modes[4];
 437                DPRINTK("      640x480@72Hz\n");
 438        }
 439        if (c&0x04) {
 440                mode[num++] = vesa_modes[5];
 441                DPRINTK("      640x480@75Hz\n");
 442        }
 443        if (c&0x02) {
 444                mode[num++] = vesa_modes[7];
 445                DPRINTK("      800x600@56Hz\n");
 446        }
 447        if (c&0x01) {
 448                mode[num++] = vesa_modes[8];
 449                DPRINTK("      800x600@60Hz\n");
 450        }
 451
 452        c = block[1];
 453        if (c&0x80) {
 454                mode[num++] = vesa_modes[9];
 455                DPRINTK("      800x600@72Hz\n");
 456        }
 457        if (c&0x40) {
 458                mode[num++] = vesa_modes[10];
 459                DPRINTK("      800x600@75Hz\n");
 460        }
 461        if (c&0x20) {
 462                calc_mode_timings(832, 624, 75, &mode[num]);
 463                mode[num++].flag = FB_MODE_IS_CALCULATED;
 464                DPRINTK("      832x624@75Hz\n");
 465        }
 466        if (c&0x10) {
 467                mode[num++] = vesa_modes[12];
 468                DPRINTK("      1024x768@87Hz Interlaced\n");
 469        }
 470        if (c&0x08) {
 471                mode[num++] = vesa_modes[13];
 472                DPRINTK("      1024x768@60Hz\n");
 473        }
 474        if (c&0x04) {
 475                mode[num++] = vesa_modes[14];
 476                DPRINTK("      1024x768@70Hz\n");
 477        }
 478        if (c&0x02) {
 479                mode[num++] = vesa_modes[15];
 480                DPRINTK("      1024x768@75Hz\n");
 481        }
 482        if (c&0x01) {
 483                mode[num++] = vesa_modes[21];
 484                DPRINTK("      1280x1024@75Hz\n");
 485        }
 486        c = block[2];
 487        if (c&0x80) {
 488                mode[num++] = vesa_modes[17];
 489                DPRINTK("      1152x870@75Hz\n");
 490        }
 491        DPRINTK("      Manufacturer's mask: %x\n",c&0x7F);
 492        return num;
 493}
 494
 495static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
 496{
 497        int xres, yres = 0, refresh, ratio, i;
 498
 499        xres = (block[0] + 31) * 8;
 500        if (xres <= 256)
 501                return 0;
 502
 503        ratio = (block[1] & 0xc0) >> 6;
 504        switch (ratio) {
 505        case 0:
 506                yres = xres;
 507                break;
 508        case 1:
 509                yres = (xres * 3)/4;
 510                break;
 511        case 2:
 512                yres = (xres * 4)/5;
 513                break;
 514        case 3:
 515                yres = (xres * 9)/16;
 516                break;
 517        }
 518        refresh = (block[1] & 0x3f) + 60;
 519
 520        DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
 521        for (i = 0; i < VESA_MODEDB_SIZE; i++) {
 522                if (vesa_modes[i].xres == xres &&
 523                    vesa_modes[i].yres == yres &&
 524                    vesa_modes[i].refresh == refresh) {
 525                        *mode = vesa_modes[i];
 526                        mode->flag |= FB_MODE_IS_STANDARD;
 527                        return 1;
 528                }
 529        }
 530        calc_mode_timings(xres, yres, refresh, mode);
 531        return 1;
 532}
 533
 534static int get_dst_timing(unsigned char *block,
 535                          struct fb_videomode *mode)
 536{
 537        int j, num = 0;
 538
 539        for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
 540                num += get_std_timing(block, &mode[num]);
 541
 542        return num;
 543}
 544
 545static void get_detailed_timing(unsigned char *block,
 546                                struct fb_videomode *mode)
 547{
 548        mode->xres = H_ACTIVE;
 549        mode->yres = V_ACTIVE;
 550        mode->pixclock = PIXEL_CLOCK;
 551        mode->pixclock /= 1000;
 552        mode->pixclock = KHZ2PICOS(mode->pixclock);
 553        mode->right_margin = H_SYNC_OFFSET;
 554        mode->left_margin = (H_ACTIVE + H_BLANKING) -
 555                (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
 556        mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
 557                V_SYNC_WIDTH;
 558        mode->lower_margin = V_SYNC_OFFSET;
 559        mode->hsync_len = H_SYNC_WIDTH;
 560        mode->vsync_len = V_SYNC_WIDTH;
 561        if (HSYNC_POSITIVE)
 562                mode->sync |= FB_SYNC_HOR_HIGH_ACT;
 563        if (VSYNC_POSITIVE)
 564                mode->sync |= FB_SYNC_VERT_HIGH_ACT;
 565        mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
 566                                     (V_ACTIVE + V_BLANKING));
 567        if (INTERLACED) {
 568                mode->yres *= 2;
 569                mode->upper_margin *= 2;
 570                mode->lower_margin *= 2;
 571                mode->vsync_len *= 2;
 572                mode->vmode |= FB_VMODE_INTERLACED;
 573        }
 574        mode->flag = FB_MODE_IS_DETAILED;
 575
 576        DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);
 577        DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
 578               H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
 579        DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
 580               V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
 581        DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
 582               (VSYNC_POSITIVE) ? "+" : "-");
 583}
 584
 585/**
 586 * fb_create_modedb - create video mode database
 587 * @edid: EDID data
 588 * @dbsize: database size
 589 *
 590 * RETURNS: struct fb_videomode, @dbsize contains length of database
 591 *
 592 * DESCRIPTION:
 593 * This function builds a mode database using the contents of the EDID
 594 * data
 595 */
 596static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
 597{
 598        struct fb_videomode *mode, *m;
 599        unsigned char *block;
 600        int num = 0, i, first = 1;
 601
 602        mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
 603        if (mode == NULL)
 604                return NULL;
 605
 606        if (edid == NULL || !edid_checksum(edid) ||
 607            !edid_check_header(edid)) {
 608                kfree(mode);
 609                return NULL;
 610        }
 611
 612        *dbsize = 0;
 613
 614        DPRINTK("   Detailed Timings\n");
 615        block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 616        for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
 617                if (!(block[0] == 0x00 && block[1] == 0x00)) {
 618                        get_detailed_timing(block, &mode[num]);
 619                        if (first) {
 620                                mode[num].flag |= FB_MODE_IS_FIRST;
 621                                first = 0;
 622                        }
 623                        num++;
 624                }
 625        }
 626
 627        DPRINTK("   Supported VESA Modes\n");
 628        block = edid + ESTABLISHED_TIMING_1;
 629        num += get_est_timing(block, &mode[num]);
 630
 631        DPRINTK("   Standard Timings\n");
 632        block = edid + STD_TIMING_DESCRIPTIONS_START;
 633        for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
 634                num += get_std_timing(block, &mode[num]);
 635
 636        block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 637        for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
 638                if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
 639                        num += get_dst_timing(block + 5, &mode[num]);
 640        }
 641
 642        /* Yikes, EDID data is totally useless */
 643        if (!num) {
 644                kfree(mode);
 645                return NULL;
 646        }
 647
 648        *dbsize = num;
 649        m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);
 650        if (!m)
 651                return mode;
 652        memmove(m, mode, num * sizeof(struct fb_videomode));
 653        kfree(mode);
 654        return m;
 655}
 656
 657/**
 658 * fb_destroy_modedb - destroys mode database
 659 * @modedb: mode database to destroy
 660 *
 661 * DESCRIPTION:
 662 * Destroy mode database created by fb_create_modedb
 663 */
 664void fb_destroy_modedb(struct fb_videomode *modedb)
 665{
 666        kfree(modedb);
 667}
 668
 669static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
 670{
 671        int i, retval = 1;
 672        unsigned char *block;
 673
 674        block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 675
 676        DPRINTK("      Monitor Operating Limits: ");
 677
 678        for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
 679                if (edid_is_limits_block(block)) {
 680                        specs->hfmin = H_MIN_RATE * 1000;
 681                        specs->hfmax = H_MAX_RATE * 1000;
 682                        specs->vfmin = V_MIN_RATE;
 683                        specs->vfmax = V_MAX_RATE;
 684                        specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
 685                        specs->gtf = (GTF_SUPPORT) ? 1 : 0;
 686                        retval = 0;
 687                        DPRINTK("From EDID\n");
 688                        break;
 689                }
 690        }
 691
 692        /* estimate monitor limits based on modes supported */
 693        if (retval) {
 694                struct fb_videomode *modes, *mode;
 695                int num_modes, hz, hscan, pixclock;
 696                int vtotal, htotal;
 697
 698                modes = fb_create_modedb(edid, &num_modes);
 699                if (!modes) {
 700                        DPRINTK("None Available\n");
 701                        return 1;
 702                }
 703
 704                retval = 0;
 705                for (i = 0; i < num_modes; i++) {
 706                        mode = &modes[i];
 707                        pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
 708                        htotal = mode->xres + mode->right_margin + mode->hsync_len
 709                                + mode->left_margin;
 710                        vtotal = mode->yres + mode->lower_margin + mode->vsync_len
 711                                + mode->upper_margin;
 712
 713                        if (mode->vmode & FB_VMODE_INTERLACED)
 714                                vtotal /= 2;
 715
 716                        if (mode->vmode & FB_VMODE_DOUBLE)
 717                                vtotal *= 2;
 718
 719                        hscan = (pixclock + htotal / 2) / htotal;
 720                        hscan = (hscan + 500) / 1000 * 1000;
 721                        hz = (hscan + vtotal / 2) / vtotal;
 722
 723                        if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
 724                                specs->dclkmax = pixclock;
 725
 726                        if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
 727                                specs->dclkmin = pixclock;
 728
 729                        if (specs->hfmax == 0 || specs->hfmax < hscan)
 730                                specs->hfmax = hscan;
 731
 732                        if (specs->hfmin == 0 || specs->hfmin > hscan)
 733                                specs->hfmin = hscan;
 734
 735                        if (specs->vfmax == 0 || specs->vfmax < hz)
 736                                specs->vfmax = hz;
 737
 738                        if (specs->vfmin == 0 || specs->vfmin > hz)
 739                                specs->vfmin = hz;
 740                }
 741                DPRINTK("Extrapolated\n");
 742                fb_destroy_modedb(modes);
 743        }
 744        DPRINTK("           H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
 745                specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
 746                specs->vfmax, specs->dclkmax/1000000);
 747        return retval;
 748}
 749
 750static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
 751{
 752        unsigned char c, *block;
 753
 754        block = edid + EDID_STRUCT_DISPLAY;
 755
 756        fb_get_monitor_limits(edid, specs);
 757
 758        c = block[0] & 0x80;
 759        specs->input = 0;
 760        if (c) {
 761                specs->input |= FB_DISP_DDI;
 762                DPRINTK("      Digital Display Input");
 763        } else {
 764                DPRINTK("      Analog Display Input: Input Voltage - ");
 765                switch ((block[0] & 0x60) >> 5) {
 766                case 0:
 767                        DPRINTK("0.700V/0.300V");
 768                        specs->input |= FB_DISP_ANA_700_300;
 769                        break;
 770                case 1:
 771                        DPRINTK("0.714V/0.286V");
 772                        specs->input |= FB_DISP_ANA_714_286;
 773                        break;
 774                case 2:
 775                        DPRINTK("1.000V/0.400V");
 776                        specs->input |= FB_DISP_ANA_1000_400;
 777                        break;
 778                case 3:
 779                        DPRINTK("0.700V/0.000V");
 780                        specs->input |= FB_DISP_ANA_700_000;
 781                        break;
 782                }
 783        }
 784        DPRINTK("\n      Sync: ");
 785        c = block[0] & 0x10;
 786        if (c)
 787                DPRINTK("      Configurable signal level\n");
 788        c = block[0] & 0x0f;
 789        specs->signal = 0;
 790        if (c & 0x10) {
 791                DPRINTK("Blank to Blank ");
 792                specs->signal |= FB_SIGNAL_BLANK_BLANK;
 793        }
 794        if (c & 0x08) {
 795                DPRINTK("Separate ");
 796                specs->signal |= FB_SIGNAL_SEPARATE;
 797        }
 798        if (c & 0x04) {
 799                DPRINTK("Composite ");
 800                specs->signal |= FB_SIGNAL_COMPOSITE;
 801        }
 802        if (c & 0x02) {
 803                DPRINTK("Sync on Green ");
 804                specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
 805        }
 806        if (c & 0x01) {
 807                DPRINTK("Serration on ");
 808                specs->signal |= FB_SIGNAL_SERRATION_ON;
 809        }
 810        DPRINTK("\n");
 811        specs->max_x = block[1];
 812        specs->max_y = block[2];
 813        DPRINTK("      Max H-size in cm: ");
 814        if (specs->max_x)
 815                DPRINTK("%d\n", specs->max_x);
 816        else
 817                DPRINTK("variable\n");
 818        DPRINTK("      Max V-size in cm: ");
 819        if (specs->max_y)
 820                DPRINTK("%d\n", specs->max_y);
 821        else
 822                DPRINTK("variable\n");
 823
 824        c = block[3];
 825        specs->gamma = c+100;
 826        DPRINTK("      Gamma: ");
 827        DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
 828
 829        get_dpms_capabilities(block[4], specs);
 830
 831        switch ((block[4] & 0x18) >> 3) {
 832        case 0:
 833                DPRINTK("      Monochrome/Grayscale\n");
 834                specs->input |= FB_DISP_MONO;
 835                break;
 836        case 1:
 837                DPRINTK("      RGB Color Display\n");
 838                specs->input |= FB_DISP_RGB;
 839                break;
 840        case 2:
 841                DPRINTK("      Non-RGB Multicolor Display\n");
 842                specs->input |= FB_DISP_MULTI;
 843                break;
 844        default:
 845                DPRINTK("      Unknown\n");
 846                specs->input |= FB_DISP_UNKNOWN;
 847                break;
 848        }
 849
 850        get_chroma(block, specs);
 851
 852        specs->misc = 0;
 853        c = block[4] & 0x7;
 854        if (c & 0x04) {
 855                DPRINTK("      Default color format is primary\n");
 856                specs->misc |= FB_MISC_PRIM_COLOR;
 857        }
 858        if (c & 0x02) {
 859                DPRINTK("      First DETAILED Timing is preferred\n");
 860                specs->misc |= FB_MISC_1ST_DETAIL;
 861        }
 862        if (c & 0x01) {
 863                printk("      Display is GTF capable\n");
 864                specs->gtf = 1;
 865        }
 866}
 867
 868int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
 869{
 870        int i;
 871        unsigned char *block;
 872
 873        if (edid == NULL || var == NULL)
 874                return 1;
 875
 876        if (!(edid_checksum(edid)))
 877                return 1;
 878
 879        if (!(edid_check_header(edid)))
 880                return 1;
 881
 882        block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 883
 884        for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
 885                if (edid_is_timing_block(block)) {
 886                        var->xres = var->xres_virtual = H_ACTIVE;
 887                        var->yres = var->yres_virtual = V_ACTIVE;
 888                        var->height = var->width = 0;
 889                        var->right_margin = H_SYNC_OFFSET;
 890                        var->left_margin = (H_ACTIVE + H_BLANKING) -
 891                                (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
 892                        var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
 893                                V_SYNC_WIDTH;
 894                        var->lower_margin = V_SYNC_OFFSET;
 895                        var->hsync_len = H_SYNC_WIDTH;
 896                        var->vsync_len = V_SYNC_WIDTH;
 897                        var->pixclock = PIXEL_CLOCK;
 898                        var->pixclock /= 1000;
 899                        var->pixclock = KHZ2PICOS(var->pixclock);
 900
 901                        if (HSYNC_POSITIVE)
 902                                var->sync |= FB_SYNC_HOR_HIGH_ACT;
 903                        if (VSYNC_POSITIVE)
 904                                var->sync |= FB_SYNC_VERT_HIGH_ACT;
 905                        return 0;
 906                }
 907        }
 908        return 1;
 909}
 910
 911void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
 912{
 913        unsigned char *block;
 914        int i, found = 0;
 915
 916        if (edid == NULL)
 917                return;
 918
 919        if (!(edid_checksum(edid)))
 920                return;
 921
 922        if (!(edid_check_header(edid)))
 923                return;
 924
 925        memset(specs, 0, sizeof(struct fb_monspecs));
 926
 927        specs->version = edid[EDID_STRUCT_VERSION];
 928        specs->revision = edid[EDID_STRUCT_REVISION];
 929
 930        DPRINTK("========================================\n");
 931        DPRINTK("Display Information (EDID)\n");
 932        DPRINTK("========================================\n");
 933        DPRINTK("   EDID Version %d.%d\n", (int) specs->version,
 934               (int) specs->revision);
 935
 936        parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
 937
 938        block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 939        for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
 940                if (edid_is_serial_block(block)) {
 941                        copy_string(block, specs->serial_no);
 942                        DPRINTK("   Serial Number: %s\n", specs->serial_no);
 943                } else if (edid_is_ascii_block(block)) {
 944                        copy_string(block, specs->ascii);
 945                        DPRINTK("   ASCII Block: %s\n", specs->ascii);
 946                } else if (edid_is_monitor_block(block)) {
 947                        copy_string(block, specs->monitor);
 948                        DPRINTK("   Monitor Name: %s\n", specs->monitor);
 949                }
 950        }
 951
 952        DPRINTK("   Display Characteristics:\n");
 953        get_monspecs(edid, specs);
 954
 955        specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
 956
 957        /*
 958         * Workaround for buggy EDIDs that sets that the first
 959         * detailed timing is preferred but has not detailed
 960         * timing specified
 961         */
 962        for (i = 0; i < specs->modedb_len; i++) {
 963                if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
 964                        found = 1;
 965                        break;
 966                }
 967        }
 968
 969        if (!found)
 970                specs->misc &= ~FB_MISC_1ST_DETAIL;
 971
 972        DPRINTK("========================================\n");
 973}
 974
 975/*
 976 * VESA Generalized Timing Formula (GTF)
 977 */
 978
 979#define FLYBACK                     550
 980#define V_FRONTPORCH                1
 981#define H_OFFSET                    40
 982#define H_SCALEFACTOR               20
 983#define H_BLANKSCALE                128
 984#define H_GRADIENT                  600
 985#define C_VAL                       30
 986#define M_VAL                       300
 987
 988struct __fb_timings {
 989        u32 dclk;
 990        u32 hfreq;
 991        u32 vfreq;
 992        u32 hactive;
 993        u32 vactive;
 994        u32 hblank;
 995        u32 vblank;
 996        u32 htotal;
 997        u32 vtotal;
 998};
 999
1000/**
1001 * fb_get_vblank - get vertical blank time
1002 * @hfreq: horizontal freq
1003 *
1004 * DESCRIPTION:
1005 * vblank = right_margin + vsync_len + left_margin
1006 *
1007 *    given: right_margin = 1 (V_FRONTPORCH)
1008 *           vsync_len    = 3
1009 *           flyback      = 550
1010 *
1011 *                          flyback * hfreq
1012 *           left_margin  = --------------- - vsync_len
1013 *                           1000000
1014 */
1015static u32 fb_get_vblank(u32 hfreq)
1016{
1017        u32 vblank;
1018
1019        vblank = (hfreq * FLYBACK)/1000;
1020        vblank = (vblank + 500)/1000;
1021        return (vblank + V_FRONTPORCH);
1022}
1023
1024/**
1025 * fb_get_hblank_by_freq - get horizontal blank time given hfreq
1026 * @hfreq: horizontal freq
1027 * @xres: horizontal resolution in pixels
1028 *
1029 * DESCRIPTION:
1030 *
1031 *           xres * duty_cycle
1032 * hblank = ------------------
1033 *           100 - duty_cycle
1034 *
1035 * duty cycle = percent of htotal assigned to inactive display
1036 * duty cycle = C - (M/Hfreq)
1037 *
1038 * where: C = ((offset - scale factor) * blank_scale)
1039 *            -------------------------------------- + scale factor
1040 *                        256
1041 *        M = blank_scale * gradient
1042 *
1043 */
1044static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
1045{
1046        u32 c_val, m_val, duty_cycle, hblank;
1047
1048        c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
1049                 H_SCALEFACTOR) * 1000;
1050        m_val = (H_BLANKSCALE * H_GRADIENT)/256;
1051        m_val = (m_val * 1000000)/hfreq;
1052        duty_cycle = c_val - m_val;
1053        hblank = (xres * duty_cycle)/(100000 - duty_cycle);
1054        return (hblank);
1055}
1056
1057/**
1058 * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
1059 * @dclk: pixelclock in Hz
1060 * @xres: horizontal resolution in pixels
1061 *
1062 * DESCRIPTION:
1063 *
1064 *           xres * duty_cycle
1065 * hblank = ------------------
1066 *           100 - duty_cycle
1067 *
1068 * duty cycle = percent of htotal assigned to inactive display
1069 * duty cycle = C - (M * h_period)
1070 *
1071 * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
1072 *                   -----------------------------------------------
1073 *                                    2 * M
1074 *        M = 300;
1075 *        C = 30;
1076
1077 */
1078static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
1079{
1080        u32 duty_cycle, h_period, hblank;
1081
1082        dclk /= 1000;
1083        h_period = 100 - C_VAL;
1084        h_period *= h_period;
1085        h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
1086        h_period *= 10000;
1087
1088        h_period = int_sqrt(h_period);
1089        h_period -= (100 - C_VAL) * 100;
1090        h_period *= 1000;
1091        h_period /= 2 * M_VAL;
1092
1093        duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
1094        hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
1095        hblank &= ~15;
1096        return (hblank);
1097}
1098
1099/**
1100 * fb_get_hfreq - estimate hsync
1101 * @vfreq: vertical refresh rate
1102 * @yres: vertical resolution
1103 *
1104 * DESCRIPTION:
1105 *
1106 *          (yres + front_port) * vfreq * 1000000
1107 * hfreq = -------------------------------------
1108 *          (1000000 - (vfreq * FLYBACK)
1109 *
1110 */
1111
1112static u32 fb_get_hfreq(u32 vfreq, u32 yres)
1113{
1114        u32 divisor, hfreq;
1115
1116        divisor = (1000000 - (vfreq * FLYBACK))/1000;
1117        hfreq = (yres + V_FRONTPORCH) * vfreq  * 1000;
1118        return (hfreq/divisor);
1119}
1120
1121static void fb_timings_vfreq(struct __fb_timings *timings)
1122{
1123        timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
1124        timings->vblank = fb_get_vblank(timings->hfreq);
1125        timings->vtotal = timings->vactive + timings->vblank;
1126        timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
1127                                                 timings->hactive);
1128        timings->htotal = timings->hactive + timings->hblank;
1129        timings->dclk = timings->htotal * timings->hfreq;
1130}
1131
1132static void fb_timings_hfreq(struct __fb_timings *timings)
1133{
1134        timings->vblank = fb_get_vblank(timings->hfreq);
1135        timings->vtotal = timings->vactive + timings->vblank;
1136        timings->vfreq = timings->hfreq/timings->vtotal;
1137        timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
1138                                                 timings->hactive);
1139        timings->htotal = timings->hactive + timings->hblank;
1140        timings->dclk = timings->htotal * timings->hfreq;
1141}
1142
1143static void fb_timings_dclk(struct __fb_timings *timings)
1144{
1145        timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
1146                                                timings->hactive);
1147        timings->htotal = timings->hactive + timings->hblank;
1148        timings->hfreq = timings->dclk/timings->htotal;
1149        timings->vblank = fb_get_vblank(timings->hfreq);
1150        timings->vtotal = timings->vactive + timings->vblank;
1151        timings->vfreq = timings->hfreq/timings->vtotal;
1152}
1153
1154/*
1155 * fb_get_mode - calculates video mode using VESA GTF
1156 * @flags: if: 0 - maximize vertical refresh rate
1157 *             1 - vrefresh-driven calculation;
1158 *             2 - hscan-driven calculation;
1159 *             3 - pixelclock-driven calculation;
1160 * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock
1161 * @var: pointer to fb_var_screeninfo
1162 * @info: pointer to fb_info
1163 *
1164 * DESCRIPTION:
1165 * Calculates video mode based on monitor specs using VESA GTF.
1166 * The GTF is best for VESA GTF compliant monitors but is
1167 * specifically formulated to work for older monitors as well.
1168 *
1169 * If @flag==0, the function will attempt to maximize the
1170 * refresh rate.  Otherwise, it will calculate timings based on
1171 * the flag and accompanying value.
1172 *
1173 * If FB_IGNOREMON bit is set in @flags, monitor specs will be
1174 * ignored and @var will be filled with the calculated timings.
1175 *
1176 * All calculations are based on the VESA GTF Spreadsheet
1177 * available at VESA's public ftp (http://www.vesa.org).
1178 *
1179 * NOTES:
1180 * The timings generated by the GTF will be different from VESA
1181 * DMT.  It might be a good idea to keep a table of standard
1182 * VESA modes as well.  The GTF may also not work for some displays,
1183 * such as, and especially, analog TV.
1184 *
1185 * REQUIRES:
1186 * A valid info->monspecs, otherwise 'safe numbers' will be used.
1187 */
1188int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
1189{
1190        struct __fb_timings *timings;
1191        u32 interlace = 1, dscan = 1;
1192        u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0;
1193
1194
1195        timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL);
1196
1197        if (!timings)
1198                return -ENOMEM;
1199
1200        /*
1201         * If monspecs are invalid, use values that are enough
1202         * for 640x480@60
1203         */
1204        if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
1205            !info->monspecs.dclkmax ||
1206            info->monspecs.hfmax < info->monspecs.hfmin ||
1207            info->monspecs.vfmax < info->monspecs.vfmin ||
1208            info->monspecs.dclkmax < info->monspecs.dclkmin) {
1209                hfmin = 29000; hfmax = 30000;
1210                vfmin = 60; vfmax = 60;
1211                dclkmin = 0; dclkmax = 25000000;
1212        } else {
1213                hfmin = info->monspecs.hfmin;
1214                hfmax = info->monspecs.hfmax;
1215                vfmin = info->monspecs.vfmin;
1216                vfmax = info->monspecs.vfmax;
1217                dclkmin = info->monspecs.dclkmin;
1218                dclkmax = info->monspecs.dclkmax;
1219        }
1220
1221        timings->hactive = var->xres;
1222        timings->vactive = var->yres;
1223        if (var->vmode & FB_VMODE_INTERLACED) {
1224                timings->vactive /= 2;
1225                interlace = 2;
1226        }
1227        if (var->vmode & FB_VMODE_DOUBLE) {
1228                timings->vactive *= 2;
1229                dscan = 2;
1230        }
1231
1232        switch (flags & ~FB_IGNOREMON) {
1233        case FB_MAXTIMINGS: /* maximize refresh rate */
1234                timings->hfreq = hfmax;
1235                fb_timings_hfreq(timings);
1236                if (timings->vfreq > vfmax) {
1237                        timings->vfreq = vfmax;
1238                        fb_timings_vfreq(timings);
1239                }
1240                if (timings->dclk > dclkmax) {
1241                        timings->dclk = dclkmax;
1242                        fb_timings_dclk(timings);
1243                }
1244                break;
1245        case FB_VSYNCTIMINGS: /* vrefresh driven */
1246                timings->vfreq = val;
1247                fb_timings_vfreq(timings);
1248                break;
1249        case FB_HSYNCTIMINGS: /* hsync driven */
1250                timings->hfreq = val;
1251                fb_timings_hfreq(timings);
1252                break;
1253        case FB_DCLKTIMINGS: /* pixelclock driven */
1254                timings->dclk = PICOS2KHZ(val) * 1000;
1255                fb_timings_dclk(timings);
1256                break;
1257        default:
1258                err = -EINVAL;
1259
1260        }
1261
1262        if (err || (!(flags & FB_IGNOREMON) &&
1263            (timings->vfreq < vfmin || timings->vfreq > vfmax ||
1264             timings->hfreq < hfmin || timings->hfreq > hfmax ||
1265             timings->dclk < dclkmin || timings->dclk > dclkmax))) {
1266                err = -EINVAL;
1267        } else {
1268                var->pixclock = KHZ2PICOS(timings->dclk/1000);
1269                var->hsync_len = (timings->htotal * 8)/100;
1270                var->right_margin = (timings->hblank/2) - var->hsync_len;
1271                var->left_margin = timings->hblank - var->right_margin -
1272                        var->hsync_len;
1273                var->vsync_len = (3 * interlace)/dscan;
1274                var->lower_margin = (1 * interlace)/dscan;
1275                var->upper_margin = (timings->vblank * interlace)/dscan -
1276                        (var->vsync_len + var->lower_margin);
1277        }
1278
1279        kfree(timings);
1280        return err;
1281}
1282#else
1283int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
1284{
1285        return 1;
1286}
1287void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
1288{
1289        specs = NULL;
1290}
1291void fb_destroy_modedb(struct fb_videomode *modedb)
1292{
1293}
1294int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
1295                struct fb_info *info)
1296{
1297        return -EINVAL;
1298}
1299#endif /* CONFIG_FB_MODE_HELPERS */
1300
1301/*
1302 * fb_validate_mode - validates var against monitor capabilities
1303 * @var: pointer to fb_var_screeninfo
1304 * @info: pointer to fb_info
1305 *
1306 * DESCRIPTION:
1307 * Validates video mode against monitor capabilities specified in
1308 * info->monspecs.
1309 *
1310 * REQUIRES:
1311 * A valid info->monspecs.
1312 */
1313int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
1314{
1315        u32 hfreq, vfreq, htotal, vtotal, pixclock;
1316        u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
1317
1318        /*
1319         * If monspecs are invalid, use values that are enough
1320         * for 640x480@60
1321         */
1322        if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
1323            !info->monspecs.dclkmax ||
1324            info->monspecs.hfmax < info->monspecs.hfmin ||
1325            info->monspecs.vfmax < info->monspecs.vfmin ||
1326            info->monspecs.dclkmax < info->monspecs.dclkmin) {
1327                hfmin = 29000; hfmax = 30000;
1328                vfmin = 60; vfmax = 60;
1329                dclkmin = 0; dclkmax = 25000000;
1330        } else {
1331                hfmin = info->monspecs.hfmin;
1332                hfmax = info->monspecs.hfmax;
1333                vfmin = info->monspecs.vfmin;
1334                vfmax = info->monspecs.vfmax;
1335                dclkmin = info->monspecs.dclkmin;
1336                dclkmax = info->monspecs.dclkmax;
1337        }
1338
1339        if (!var->pixclock)
1340                return -EINVAL;
1341        pixclock = PICOS2KHZ(var->pixclock) * 1000;
1342
1343        htotal = var->xres + var->right_margin + var->hsync_len +
1344                var->left_margin;
1345        vtotal = var->yres + var->lower_margin + var->vsync_len +
1346                var->upper_margin;
1347
1348        if (var->vmode & FB_VMODE_INTERLACED)
1349                vtotal /= 2;
1350        if (var->vmode & FB_VMODE_DOUBLE)
1351                vtotal *= 2;
1352
1353        hfreq = pixclock/htotal;
1354        hfreq = (hfreq + 500) / 1000 * 1000;
1355
1356        vfreq = hfreq/vtotal;
1357
1358        return (vfreq < vfmin || vfreq > vfmax ||
1359                hfreq < hfmin || hfreq > hfmax ||
1360                pixclock < dclkmin || pixclock > dclkmax) ?
1361                -EINVAL : 0;
1362}
1363
1364#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
1365
1366/*
1367 * We need to ensure that the EDID block is only returned for
1368 * the primary graphics adapter.
1369 */
1370
1371const unsigned char *fb_firmware_edid(struct device *device)
1372{
1373        struct pci_dev *dev = NULL;
1374        struct resource *res = NULL;
1375        unsigned char *edid = NULL;
1376
1377        if (device)
1378                dev = to_pci_dev(device);
1379
1380        if (dev)
1381                res = &dev->resource[PCI_ROM_RESOURCE];
1382
1383        if (res && res->flags & IORESOURCE_ROM_SHADOW)
1384                edid = edid_info.dummy;
1385
1386        return edid;
1387}
1388#else
1389const unsigned char *fb_firmware_edid(struct device *device)
1390{
1391        return NULL;
1392}
1393#endif
1394EXPORT_SYMBOL(fb_firmware_edid);
1395
1396EXPORT_SYMBOL(fb_parse_edid);
1397EXPORT_SYMBOL(fb_edid_to_monspecs);
1398EXPORT_SYMBOL(fb_get_mode);
1399EXPORT_SYMBOL(fb_validate_mode);
1400EXPORT_SYMBOL(fb_destroy_modedb);