Commit c42f7c1f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] fbdev: monitor detection fixes

From: James Simmons <jsimmons@infradead.org>,
      Kronos <kronos@kronoz.cjb.net>

Various fixes and enhancements to the monitor hardware detection code.  The
only driver that uses it is the radeon driver.

Old EDID parsing code was very verbose, half of the patch address this (ie.
print lots of stuff iff DEBUG).  The other big change is the FB_MODE_IS_*
stuff: we really need a way to know the origin of a video mode.  In this way
we can select video mode that comes from EDID instead of VESA or GTF.

Drivers other than radeonfb won't be affected because they cannot (yet) get
EDID from the monitor and don't use EDID related code.
parent 787bc776
......@@ -757,7 +757,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
&& rinfo->mon1_EDID) {
struct fb_var_screeninfo var;
RTRACE("Parsing EDID data for panel info\n");
if (parse_edid(rinfo->mon1_EDID, &var) == 0) {
if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) {
if (var.xres >= rinfo->panel_info.xres &&
var.yres >= rinfo->panel_info.yres)
radeon_var_to_panel_info(rinfo, &var);
......
......@@ -41,6 +41,15 @@
* EDID parser
*/
#undef DEBUG /* define this for verbose EDID parsing output */
#ifdef DEBUG
#define DPRINTK(fmt, args...) printk(fmt,## args)
#else
#define DPRINTK(fmt, args...)
#endif
const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00
};
......@@ -84,203 +93,93 @@ static int edid_check_header(unsigned char *edid)
return 1;
}
static void parse_vendor_block(unsigned char *block)
static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
{
unsigned char c[4];
c[0] = ((block[0] & 0x7c) >> 2) + '@';
c[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';
c[2] = (block[1] & 0x1f) + '@';
c[3] = 0;
printk(" Manufacturer: %s ", c);
printk("Model: %x ", block[2] + (block[3] << 8));
printk("Serial#: %u\n", block[4] + (block[5] << 8) +
(block[6] << 16) + (block[7] << 24));
printk(" Year: %u Week %u\n", block[9] + 1990, block[8]);
specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
((block[1] & 0xe0) >> 5) + '@';
specs->manufacturer[2] = (block[1] & 0x1f) + '@';
specs->manufacturer[3] = 0;
specs->model = block[2] + (block[3] << 8);
specs->serial = block[4] + (block[5] << 8) +
(block[6] << 16) + (block[7] << 24);
specs->year = block[9] + 1990;
specs->week = block[8];
DPRINTK(" Manufacturer: %s\n", specs->manufacturer);
DPRINTK(" Model: %x\n", specs->model);
DPRINTK(" Serial#: %u\n", specs->serial);
DPRINTK(" Year: %u Week %u\n", specs->year, specs->week);
}
static void parse_dpms_capabilities(unsigned char flags)
static void get_dpms_capabilities(unsigned char flags,
struct fb_monspecs *specs)
{
printk(" DPMS: Active %s, Suspend %s, Standby %s\n",
specs->dpms = 0;
if (flags & DPMS_ACTIVE_OFF)
specs->dpms |= FB_DPMS_ACTIVE_OFF;
if (flags & DPMS_SUSPEND)
specs->dpms |= FB_DPMS_SUSPEND;
if (flags & DPMS_STANDBY)
specs->dpms |= FB_DPMS_STANDBY;
DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n",
(flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
(flags & DPMS_SUSPEND) ? "yes" : "no",
(flags & DPMS_STANDBY) ? "yes" : "no");
}
static void print_chroma(unsigned char *block)
static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
{
int tmp;
DPRINTK(" Chroma\n");
/* Chromaticity data */
printk(" Chromaticity: ");
tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
tmp *= 1000;
tmp += 512;
printk("RedX: 0.%03d ", tmp/1024);
specs->chroma.redx = tmp/1024;
DPRINTK(" RedX: 0.%03d ", specs->chroma.redx);
tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
tmp *= 1000;
tmp += 512;
printk("RedY: 0.%03d\n", tmp/1024);
specs->chroma.redy = tmp/1024;
DPRINTK("RedY: 0.%03d\n", specs->chroma.redy);
tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
tmp *= 1000;
tmp += 512;
printk(" GreenX: 0.%03d ", tmp/1024);
specs->chroma.greenx = tmp/1024;
DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx);
tmp = (block[5] & 3) | (block[0xa] << 2);
tmp *= 1000;
tmp += 512;
printk("GreenY: 0.%03d\n", tmp/1024);
specs->chroma.greeny = tmp/1024;
DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny);
tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
tmp *= 1000;
tmp += 512;
printk(" BlueX: 0.%03d ", tmp/1024);
specs->chroma.bluex = tmp/1024;
DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex);
tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
tmp *= 1000;
tmp += 512;
printk("BlueY: 0.%03d\n", tmp/1024);
specs->chroma.bluey = tmp/1024;
DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey);
tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
tmp *= 1000;
tmp += 512;
printk(" WhiteX: 0.%03d ", tmp/1024);
specs->chroma.whitex = tmp/1024;
DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex);
tmp = (block[6] & 3) | (block[0xe] << 2);
tmp *= 1000;
tmp += 512;
printk("WhiteY: 0.%03d\n", tmp/1024);
}
static void parse_display_block(unsigned char *block)
{
unsigned char c;
c = (block[0] & 0x80) >> 7;
if (c)
printk(" Digital Display Input");
else {
printk(" Analog Display Input: Input Voltage - ");
switch ((block[0] & 0x60) >> 5) {
case 0:
printk("0.700V/0.300V");
break;
case 1:
printk("0.714V/0.286V");
break;
case 2:
printk("1.000V/0.400V");
break;
case 3:
printk("0.700V/0.000V");
break;
default:
printk("unknown");
}
printk("\n");
}
c = (block[0] & 0x10) >> 4;
if (c)
printk(" Configurable signal level\n");
printk(" Sync: ");
c = block[0] & 0x0f;
if (c & 0x10)
printk("Blank to Blank ");
if (c & 0x08)
printk("Separate ");
if (c & 0x04)
printk("Composite ");
if (c & 0x02)
printk("Sync on Green ");
if (c & 0x01)
printk("Serration on ");
printk("\n");
printk(" Max H-size in cm: ");
c = block[1];
if (c)
printk("%d\n", c);
else
printk("variable\n");
printk(" Max V-size in cm: ");
c = block[2];
if (c)
printk("%d\n", c);
else
printk("variable\n");
c = block[3];
printk(" Gamma: ");
printk("%d.%d\n", (c + 100)/100, (c+100) % 100);
parse_dpms_capabilities(block[4]);
switch ((block[4] & 0x18) >> 3) {
case 0:
printk(" Monochrome/Grayscale\n");
break;
case 1:
printk(" RGB Color Display\n");
break;
case 2:
printk(" Non-RGB Multicolor Display\n");
break;
default:
printk(" Unknown\n");
break;
}
print_chroma(block);
c = block[4] & 0x7;
if (c & 0x04)
printk(" Default color format is primary\n");
if (c & 0x02)
printk(" First DETAILED Timing is preferred\n");
if (c & 0x01)
printk(" Display is GTF capable\n");
}
static void parse_std_md_block(unsigned char *block)
{
unsigned char c;
c = block[0];
if (c&0x80) printk(" 720x400@70Hz\n");
if (c&0x40) printk(" 720x400@88Hz\n");
if (c&0x20) printk(" 640x480@60Hz\n");
if (c&0x10) printk(" 640x480@67Hz\n");
if (c&0x08) printk(" 640x480@72Hz\n");
if (c&0x04) printk(" 640x480@75Hz\n");
if (c&0x02) printk(" 800x600@56Hz\n");
if (c&0x01) printk(" 800x600@60Hz\n");
c = block[1];
if (c&0x80) printk(" 800x600@72Hz\n");
if (c&0x40) printk(" 800x600@75Hz\n");
if (c&0x20) printk(" 832x624@75Hz\n");
if (c&0x10) printk(" 1024x768@87Hz (interlaced)\n");
if (c&0x08) printk(" 1024x768@60Hz\n");
if (c&0x04) printk(" 1024x768@70Hz\n");
if (c&0x02) printk(" 1024x768@75Hz\n");
if (c&0x01) printk(" 1280x1024@75Hz\n");
c = block[2];
if (c&0x80) printk(" 1152x870@75Hz\n");
printk(" Manufacturer's mask: %x\n",c&0x7F);
}
static int edid_is_timing_block(unsigned char *block)
{
if ((block[0] != 0x00) || (block[1] != 0x00) ||
(block[2] != 0x00) || (block[4] != 0x00))
return 1;
else
return 0;
specs->chroma.whitey = tmp/1024;
DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey);
}
static int edid_is_serial_block(unsigned char *block)
......@@ -323,154 +222,6 @@ static int edid_is_monitor_block(unsigned char *block)
return 0;
}
static int edid_is_color_block(unsigned char *block)
{
if ((block[0] == 0x00) && (block[1] == 0x00) &&
(block[2] == 0x00) && (block[3] == 0xfb) &&
(block[4] == 0x00))
return 1;
else
return 0;
}
static int edid_is_std_timings_block(unsigned char *block)
{
if ((block[0] == 0x00) && (block[1] == 0x00) &&
(block[2] == 0x00) && (block[3] == 0xfa) &&
(block[4] == 0x00))
return 1;
else
return 0;
}
static void parse_serial_block(unsigned char *block)
{
unsigned char c[13];
copy_string(block, c);
printk(" Serial No : %s\n", c);
}
static void parse_ascii_block(unsigned char *block)
{
unsigned char c[13];
copy_string(block, c);
printk(" %s\n", c);
}
static void parse_limits_block(unsigned char *block)
{
printk(" HorizSync : %d-%d KHz\n", H_MIN_RATE, H_MAX_RATE);
printk(" VertRefresh : %d-%d Hz\n", V_MIN_RATE, V_MAX_RATE);
if (MAX_PIXEL_CLOCK != 10*0xff)
printk(" Max Pixelclock: %d MHz\n", (int) MAX_PIXEL_CLOCK);
}
static void parse_monitor_block(unsigned char *block)
{
unsigned char c[13];
copy_string(block, c);
printk(" Monitor Name : %s\n", c);
}
static void parse_color_block(unsigned char *block)
{
printk(" Color Point : unimplemented\n");
}
static void parse_std_timing_block(unsigned char *block)
{
int xres, yres = 0, refresh, ratio, err = 1;
xres = (block[0] + 31) * 8;
if (xres <= 256)
return;
ratio = (block[1] & 0xc0) >> 6;
switch (ratio) {
case 0:
yres = xres;
break;
case 1:
yres = (xres * 3)/4;
break;
case 2:
yres = (xres * 4)/5;
break;
case 3:
yres = (xres * 9)/16;
break;
}
refresh = (block[1] & 0x3f) + 60;
printk(" %dx%d@%dHz\n", xres, yres, refresh);
err = 0;
}
static void parse_dst_timing_block(unsigned char *block)
{
int i;
block += 5;
for (i = 0; i < 5; i++, block += STD_TIMING_DESCRIPTION_SIZE)
parse_std_timing_block(block);
}
static void parse_detailed_timing_block(unsigned char *block)
{
printk(" %d MHz ", PIXEL_CLOCK/1000000);
printk("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
printk("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
printk("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
(VSYNC_POSITIVE) ? "+" : "-");
}
int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
{
int i;
unsigned char *block;
if (edid == NULL || var == NULL)
return 1;
if (!(edid_checksum(edid)))
return 1;
if (!(edid_check_header(edid)))
return 1;
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
if (edid_is_timing_block(block)) {
var->xres = var->xres_virtual = H_ACTIVE;
var->yres = var->yres_virtual = V_ACTIVE;
var->height = var->width = -1;
var->right_margin = H_SYNC_OFFSET;
var->left_margin = (H_ACTIVE + H_BLANKING) -
(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
V_SYNC_WIDTH;
var->lower_margin = V_SYNC_OFFSET;
var->hsync_len = H_SYNC_WIDTH;
var->vsync_len = V_SYNC_WIDTH;
var->pixclock = PIXEL_CLOCK;
var->pixclock /= 1000;
var->pixclock = KHZ2PICOS(var->pixclock);
if (HSYNC_POSITIVE)
var->sync |= FB_SYNC_HOR_HIGH_ACT;
if (VSYNC_POSITIVE)
var->sync |= FB_SYNC_VERT_HIGH_ACT;
return 0;
}
}
return 1;
}
static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode)
{
struct fb_var_screeninfo var;
......@@ -500,45 +251,82 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
unsigned char c;
c = block[0];
if (c&0x80)
calc_mode_timings(720, 400, 70, &mode[num++]);
if (c&0x40)
calc_mode_timings(720, 400, 88, &mode[num++]);
if (c&0x20)
if (c&0x80) {
calc_mode_timings(720, 400, 70, &mode[num]);
mode[num++].flag = FB_MODE_IS_CALCULATED;
DPRINTK(" 720x400@70Hz\n");
}
if (c&0x40) {
calc_mode_timings(720, 400, 88, &mode[num]);
mode[num++].flag = FB_MODE_IS_CALCULATED;
DPRINTK(" 720x400@88Hz\n");
}
if (c&0x20) {
mode[num++] = vesa_modes[3];
if (c&0x10)
calc_mode_timings(640, 480, 67, &mode[num++]);
if (c&0x08)
DPRINTK(" 640x480@60Hz\n");
}
if (c&0x10) {
calc_mode_timings(640, 480, 67, &mode[num]);
mode[num++].flag = FB_MODE_IS_CALCULATED;
DPRINTK(" 640x480@67Hz\n");
}
if (c&0x08) {
mode[num++] = vesa_modes[4];
if (c&0x04)
DPRINTK(" 640x480@72Hz\n");
}
if (c&0x04) {
mode[num++] = vesa_modes[5];
if (c&0x02)
DPRINTK(" 640x480@75Hz\n");
}
if (c&0x02) {
mode[num++] = vesa_modes[7];
if (c&0x01)
DPRINTK(" 800x600@56Hz\n");
}
if (c&0x01) {
mode[num++] = vesa_modes[8];
DPRINTK(" 800x600@60Hz\n");
}
c = block[1];
if (c&0x80)
if (c&0x80) {
mode[num++] = vesa_modes[9];
if (c&0x40)
DPRINTK(" 800x600@72Hz\n");
}
if (c&0x40) {
mode[num++] = vesa_modes[10];
if (c&0x20)
calc_mode_timings(832, 624, 75, &mode[num++]);
if (c&0x10)
DPRINTK(" 800x600@75Hz\n");
}
if (c&0x20) {
calc_mode_timings(832, 624, 75, &mode[num]);
mode[num++].flag = FB_MODE_IS_CALCULATED;
DPRINTK(" 832x624@75Hz\n");
}
if (c&0x10) {
mode[num++] = vesa_modes[12];
if (c&0x08)
DPRINTK(" 1024x768@87Hz Interlaced\n");
}
if (c&0x08) {
mode[num++] = vesa_modes[13];
if (c&0x04)
DPRINTK(" 1024x768@60Hz\n");
}
if (c&0x04) {
mode[num++] = vesa_modes[14];
if (c&0x02)
DPRINTK(" 1024x768@70Hz\n");
}
if (c&0x02) {
mode[num++] = vesa_modes[15];
if (c&0x01)
DPRINTK(" 1024x768@75Hz\n");
}
if (c&0x01) {
mode[num++] = vesa_modes[21];
DPRINTK(" 1280x1024@75Hz\n");
}
c = block[2];
if (c&0x80)
if (c&0x80) {
mode[num++] = vesa_modes[17];
DPRINTK(" 1152x870@75Hz\n");
}
DPRINTK(" Manufacturer's mask: %x\n",c&0x7F);
return num;
}
......@@ -567,17 +355,17 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
}
refresh = (block[1] & 0x3f) + 60;
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
for (i = 0; i < VESA_MODEDB_SIZE; i++) {
if (vesa_modes[i].xres == xres &&
vesa_modes[i].yres == yres &&
vesa_modes[i].refresh == refresh) {
*mode = vesa_modes[i];
break;
} else {
calc_mode_timings(xres, yres, refresh, mode);
break;
mode->flag |= FB_MODE_IS_STANDARD;
return 1;
}
}
calc_mode_timings(xres, yres, refresh, mode);
return 1;
}
......@@ -615,6 +403,15 @@ static void get_detailed_timing(unsigned char *block,
mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
(V_ACTIVE + V_BLANKING));
mode->vmode = 0;
mode->flag = FB_MODE_IS_DETAILED;
DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
(VSYNC_POSITIVE) ? "+" : "-");
}
/**
......@@ -647,21 +444,30 @@ struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
*dbsize = 0;
DPRINTK(" Supported VESA Modes\n");
block = edid + ESTABLISHED_TIMING_1;
num += get_est_timing(block, &mode[num]);
DPRINTK(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
num += get_std_timing(block, &mode[num]);
DPRINTK(" Detailed Timings\n");
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
int first = 1;
if (block[0] == 0x00 && block[1] == 0x00) {
if (block[3] == 0xfa) {
num += get_dst_timing(block + 5, &mode[num]);
}
} else {
get_detailed_timing(block, &mode[num]);
if (first) {
mode[num].flag |= FB_MODE_IS_FIRST;
first = 0;
}
num++;
}
}
......@@ -694,45 +500,24 @@ void fb_destroy_modedb(struct fb_videomode *modedb)
kfree(modedb);
}
/**
* fb_get_monitor_limits - get monitor operating limits
* @edid: EDID data
* @specs: fb_monspecs structure pointer
*
* DESCRIPTION:
* Gets monitor operating limits from EDID data and places them in
* @specs
*/
int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
{
int i, retval = 1;
unsigned char *block;
if (edid == NULL || specs == NULL)
return 1;
if (!(edid_checksum(edid)))
return 1;
if (!(edid_check_header(edid)))
return 1;
memset(specs, 0, sizeof(struct fb_monspecs));
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
printk("Monitor Operating Limits: ");
DPRINTK(" Monitor Operating Limits: ");
for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
if (edid_is_limits_block(block)) {
specs->hfmin = H_MIN_RATE * 1000;
specs->hfmax = H_MAX_RATE * 1000;
specs->vfmin = V_MIN_RATE;
specs->vfmax = V_MAX_RATE;
specs->dclkmax = (MAX_PIXEL_CLOCK != 10*0xff) ?
MAX_PIXEL_CLOCK * 1000000 : 0;
specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
specs->gtf = (GTF_SUPPORT) ? 1 : 0;
specs->dpms = edid[DPMS_FLAGS];
retval = 0;
printk("From EDID\n");
DPRINTK("From EDID\n");
break;
}
}
......@@ -744,7 +529,7 @@ int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
modes = fb_create_modedb(edid, &num_modes);
if (!modes) {
printk("None Available\n");
DPRINTK("None Available\n");
return 1;
}
......@@ -767,15 +552,189 @@ int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
if (specs->vfmin == 0 || specs->vfmin > hz)
specs->vfmin = hz;
}
printk("Extrapolated\n");
DPRINTK("Extrapolated\n");
fb_destroy_modedb(modes);
}
printk(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", specs->hfmin/1000, specs->hfmax/1000,
specs->vfmin, specs->vfmax, specs->dclkmax/1000000);
DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
specs->vfmax, specs->dclkmax/1000000);
return retval;
}
void show_edid(unsigned char *edid)
static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
{
unsigned char c, *block;
block = edid + EDID_STRUCT_DISPLAY;
fb_get_monitor_limits(edid, specs);
c = (block[0] & 0x80) >> 7;
specs->input = 0;
if (c) {
specs->input |= FB_DISP_DDI;
DPRINTK(" Digital Display Input");
} else {
DPRINTK(" Analog Display Input: Input Voltage - ");
switch ((block[0] & 0x60) >> 5) {
case 0:
DPRINTK("0.700V/0.300V");
specs->input |= FB_DISP_ANA_700_300;
break;
case 1:
DPRINTK("0.714V/0.286V");
specs->input |= FB_DISP_ANA_714_286;
break;
case 2:
DPRINTK("1.000V/0.400V");
specs->input |= FB_DISP_ANA_1000_400;
break;
case 3:
DPRINTK("0.700V/0.000V");
specs->input |= FB_DISP_ANA_700_000;
break;
default:
DPRINTK("unknown");
specs->input |= FB_DISP_UNKNOWN;
}
}
DPRINTK("\n Sync: ");
c = (block[0] & 0x10) >> 4;
if (c)
DPRINTK(" Configurable signal level\n");
c = block[0] & 0x0f;
specs->signal = 0;
if (c & 0x10) {
DPRINTK("Blank to Blank ");
specs->signal |= FB_SIGNAL_BLANK_BLANK;
}
if (c & 0x08) {
DPRINTK("Separate ");
specs->signal |= FB_SIGNAL_SEPARATE;
}
if (c & 0x04) {
DPRINTK("Composite ");
specs->signal |= FB_SIGNAL_COMPOSITE;
}
if (c & 0x02) {
DPRINTK("Sync on Green ");
specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
}
if (c & 0x01) {
DPRINTK("Serration on ");
specs->signal |= FB_SIGNAL_SERRATION_ON;
}
DPRINTK("\n");
specs->max_x = block[1];
specs->max_y = block[2];
DPRINTK(" Max H-size in cm: ");
if (specs->max_x)
DPRINTK("%d\n", specs->max_x);
else
DPRINTK("variable\n");
DPRINTK(" Max V-size in cm: ");
if (specs->max_y)
DPRINTK("%d\n", specs->max_y);
else
DPRINTK("variable\n");
c = block[3];
specs->gamma = c+100;
DPRINTK(" Gamma: ");
DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
get_dpms_capabilities(block[4], specs);
switch ((block[4] & 0x18) >> 3) {
case 0:
DPRINTK(" Monochrome/Grayscale\n");
specs->input |= FB_DISP_MONO;
break;
case 1:
DPRINTK(" RGB Color Display\n");
specs->input |= FB_DISP_RGB;
break;
case 2:
DPRINTK(" Non-RGB Multicolor Display\n");
specs->input |= FB_DISP_MULTI;
break;
default:
DPRINTK(" Unknown\n");
specs->input |= FB_DISP_UNKNOWN;
break;
}
get_chroma(block, specs);
specs->misc = 0;
c = block[4] & 0x7;
if (c & 0x04) {
DPRINTK(" Default color format is primary\n");
specs->misc |= FB_MISC_PRIM_COLOR;
}
if (c & 0x02) {
DPRINTK(" First DETAILED Timing is preferred\n");
specs->misc |= FB_MISC_1ST_DETAIL;
}
if (c & 0x01) {
printk(" Display is GTF capable\n");
specs->gtf = 1;
}
}
static int edid_is_timing_block(unsigned char *block)
{
if ((block[0] != 0x00) || (block[1] != 0x00) ||
(block[2] != 0x00) || (block[4] != 0x00))
return 1;
else
return 0;
}
int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
{
int i;
unsigned char *block;
if (edid == NULL || var == NULL)
return 1;
if (!(edid_checksum(edid)))
return 1;
if (!(edid_check_header(edid)))
return 1;
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
if (edid_is_timing_block(block)) {
var->xres = var->xres_virtual = H_ACTIVE;
var->yres = var->yres_virtual = V_ACTIVE;
var->height = var->width = -1;
var->right_margin = H_SYNC_OFFSET;
var->left_margin = (H_ACTIVE + H_BLANKING) -
(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
V_SYNC_WIDTH;
var->lower_margin = V_SYNC_OFFSET;
var->hsync_len = H_SYNC_WIDTH;
var->vsync_len = V_SYNC_WIDTH;
var->pixclock = PIXEL_CLOCK;
var->pixclock /= 1000;
var->pixclock = KHZ2PICOS(var->pixclock);
if (HSYNC_POSITIVE)
var->sync |= FB_SYNC_HOR_HIGH_ACT;
if (VSYNC_POSITIVE)
var->sync |= FB_SYNC_VERT_HIGH_ACT;
return 0;
}
}
return 1;
}
void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
{
unsigned char *block;
int i;
......@@ -788,83 +747,52 @@ void show_edid(unsigned char *edid)
if (!(edid_check_header(edid)))
return;
printk("========================================\n");
printk("Display Information (EDID)\n");
printk("========================================\n");
printk(" EDID Version %d.%d\n", (int) edid[EDID_STRUCT_VERSION],
(int) edid[EDID_STRUCT_REVISION]);
parse_vendor_block(edid + ID_MANUFACTURER_NAME);
memset(specs, 0, sizeof(struct fb_monspecs));
printk(" Display Characteristics:\n");
parse_display_block(edid + EDID_STRUCT_DISPLAY);
specs->version = edid[EDID_STRUCT_VERSION];
specs->revision = edid[EDID_STRUCT_REVISION];
printk(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
parse_std_timing_block(block);
DPRINTK("========================================\n");
DPRINTK("Display Information (EDID)\n");
DPRINTK("========================================\n");
DPRINTK(" EDID Version %d.%d\n", (int) specs->version,
(int) specs->revision);
printk(" Supported VESA Modes\n");
parse_std_md_block(edid + ESTABLISHED_TIMING_1);
parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
printk(" Detailed Monitor Information\n");
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
if (edid_is_serial_block(block)) {
parse_serial_block(block);
copy_string(block, specs->serial_no);
DPRINTK(" Serial Number: %s\n", specs->serial_no);
} else if (edid_is_ascii_block(block)) {
parse_ascii_block(block);
} else if (edid_is_limits_block(block)) {
parse_limits_block(block);
copy_string(block, specs->ascii);
DPRINTK(" ASCII Block: %s\n", specs->ascii);
} else if (edid_is_monitor_block(block)) {
parse_monitor_block(block);
} else if (edid_is_color_block(block)) {
parse_color_block(block);
} else if (edid_is_std_timings_block(block)) {
parse_dst_timing_block(block);
} else if (edid_is_timing_block(block)) {
parse_detailed_timing_block(block);
copy_string(block, specs->monitor);
DPRINTK(" Monitor Name: %s\n", specs->monitor);
}
}
printk("========================================\n");
}
#ifdef CONFIG_PPC_OF
char *get_EDID_from_OF(struct pci_dev *pdev)
{
static char *propnames[] =
{ "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
unsigned char *pedid = NULL;
struct device_node *dp;
int i;
DPRINTK(" Display Characteristics:\n");
get_monspecs(edid, specs);
if (pdev == NULL)
return NULL;
dp = pci_device_to_OF_node(pdev);
while (dp != NULL) {
for (i = 0; propnames[i] != NULL; ++i) {
pedid = (unsigned char *) get_property(dp, propnames[i], NULL);
if (pedid != NULL)
return pedid;
}
dp = dp->child;
}
show_edid(pedid);
return pedid;
specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
DPRINTK("========================================\n");
}
#endif
#ifdef CONFIG_X86
char *get_EDID_from_BIOS(void *dummy)
char *get_EDID_from_firmware(struct device *dev)
{
unsigned char *pedid = edid_info.dummy;
unsigned char *pedid = NULL;
#if defined(CONFIG_EDID_FIRMWARE) && defined(CONFIG_X86)
pedid = edid_info.dummy;
if (!pedid)
return NULL;
show_edid(pedid);
return pedid;
}
#endif
return pedid;
}
/*
* VESA Generalized Timing Formula (GTF)
......@@ -1179,7 +1107,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
* REQUIRES:
* A valid info->monspecs.
*/
int fb_validate_mode(struct fb_var_screeninfo *var, struct fb_info *info)
int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
{
u32 hfreq, vfreq, htotal, vtotal, pixclock;
u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
......@@ -1228,16 +1156,12 @@ int fb_validate_mode(struct fb_var_screeninfo *var, struct fb_info *info)
-EINVAL : 0;
}
EXPORT_SYMBOL(parse_edid);
EXPORT_SYMBOL(show_edid);
#ifdef CONFIG_X86
EXPORT_SYMBOL(get_EDID_from_BIOS);
#endif
#ifdef CONFIG_PPC_OF
EXPORT_SYMBOL(get_EDID_from_OF);
#endif
EXPORT_SYMBOL(fb_get_monitor_limits);
EXPORT_SYMBOL(fb_parse_edid);
EXPORT_SYMBOL(fb_edid_to_monspecs);
EXPORT_SYMBOL(get_EDID_from_firmware);
EXPORT_SYMBOL(fb_get_mode);
EXPORT_SYMBOL(fb_validate_mode);
EXPORT_SYMBOL(fb_create_modedb);
EXPORT_SYMBOL(fb_destroy_modedb);
EXPORT_SYMBOL(fb_get_monitor_limits);
......@@ -39,7 +39,7 @@ const char *global_mode_option = NULL;
#define DEFAULT_MODEDB_INDEX 0
static const struct fb_videomode modedb[] __initdata = {
static const struct fb_videomode modedb[] = {
{
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
......@@ -130,11 +130,11 @@ static const struct fb_videomode modedb[] __initdata = {
0, FB_VMODE_NONINTERLACED
}, {
/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
"LCD_XGA_75", 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}, {
/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
"LCD_XGA_60", 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}, {
/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
......@@ -254,109 +254,128 @@ static const struct fb_videomode modedb[] __initdata = {
const struct fb_videomode vesa_modes[] = {
/* 0 640x350-85 VESA */
{ NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3,
FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
/* 1 640x400-85 VESA */
{ NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 2 720x400-85 VESA */
{ NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 3 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED },
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 4 640x480-72 VESA */
{ NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
0, FB_VMODE_NONINTERLACED },
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 5 640x480-75 VESA */
{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
0, FB_VMODE_NONINTERLACED },
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 6 640x480-85 VESA */
{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
0, FB_VMODE_NONINTERLACED },
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 7 800x600-56 VESA */
{ NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 8 800x600-60 VESA */
{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 9 800x600-72 VESA */
{ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 10 800x600-75 VESA */
{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 11 800x600-85 VESA */
{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 12 1024x768i-43 VESA */
{ NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
/* 13 1024x768-60 VESA */
{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
0, FB_VMODE_NONINTERLACED },
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 14 1024x768-70 VESA */
{ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
0, FB_VMODE_NONINTERLACED },
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 15 1024x768-75 VESA */
{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 16 1024x768-85 VESA */
{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 17 1152x864-75 VESA */
{ NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 18 1280x960-60 VESA */
{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 19 1280x960-85 VESA */
{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 20 1280x1024-60 VESA */
{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 21 1280x1024-75 VESA */
{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 22 1280x1024-85 VESA */
{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 23 1600x1200-60 VESA */
{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 24 1600x1200-65 VESA */
{ NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 25 1600x1200-70 VESA */
{ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 26 1600x1200-75 VESA */
{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 27 1600x1200-85 VESA */
{ NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 28 1792x1344-60 VESA */
{ NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 29 1792x1344-75 VESA */
{ NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 30 1856x1392-60 VESA */
{ NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 31 1856x1392-75 VESA */
{ NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 32 1920x1440-60 VESA */
{ NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 33 1920x1440-75 VESA */
{ NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
static int __init my_atoi(const char *name)
static int my_atoi(const char *name)
{
int val = 0;
......@@ -447,11 +466,11 @@ int __fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
*
*/
int __init fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info, const char *mode_option,
const struct fb_videomode *db, unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp)
int fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info, const char *mode_option,
const struct fb_videomode *db, unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp)
{
int i, j;
......
......@@ -236,15 +236,71 @@ struct fb_con2fbmap {
#define VESA_HSYNC_SUSPEND 2
#define VESA_POWERDOWN 3
/* Definitions below are used in the parsed monitor specs */
#define FB_DPMS_ACTIVE_OFF 1
#define FB_DPMS_SUSPEND 2
#define FB_DPMS_STANDBY 4
#define FB_DISP_DDI 1
#define FB_DISP_ANA_700_300 2
#define FB_DISP_ANA_714_286 4
#define FB_DISP_ANA_1000_400 8
#define FB_DISP_ANA_700_000 16
#define FB_DISP_MONO 32
#define FB_DISP_RGB 64
#define FB_DISP_MULTI 128
#define FB_DISP_UNKNOWN 256
#define FB_SIGNAL_NONE 0
#define FB_SIGNAL_BLANK_BLANK 1
#define FB_SIGNAL_SEPARATE 2
#define FB_SIGNAL_COMPOSITE 4
#define FB_SIGNAL_SYNC_ON_GREEN 8
#define FB_SIGNAL_SERRATION_ON 16
#define FB_MISC_PRIM_COLOR 1
#define FB_MISC_1ST_DETAIL 2 /* First Detailed Timing is preferred */
struct fb_chroma {
__u32 redx; /* in fraction of 1024 */
__u32 greenx;
__u32 bluex;
__u32 whitex;
__u32 redy;
__u32 greeny;
__u32 bluey;
__u32 whitey;
};
struct fb_monspecs {
struct fb_chroma chroma;
struct fb_videomode *modedb; /* mode database */
__u8 manufacturer[4]; /* Manufacturer */
__u8 monitor[14]; /* Monitor String */
__u8 serial_no[14]; /* Serial Number */
__u8 ascii[14]; /* ? */
__u32 modedb_len; /* mode database length */
__u32 model; /* Monitor Model */
__u32 serial; /* Serial Number - Integer */
__u32 year; /* Year manufactured */
__u32 week; /* Week Manufactured */
__u32 hfmin; /* hfreq lower limit (Hz) */
__u32 hfmax; /* hfreq upper limit (Hz) */
__u32 hfmax; /* hfreq upper limit (Hz) */
__u32 dclkmin; /* pixelclock lower limit (Hz) */
__u32 dclkmax; /* pixelclock upper limit (Hz) */
__u16 input; /* display type - see FB_DISP_* */
__u16 dpms; /* DPMS support - see FB_DPMS_ */
__u16 signal; /* Signal Type - see FB_SIGNAL_* */
__u16 vfmin; /* vfreq lower limit (Hz) */
__u16 vfmax; /* vfreq upper limit (Hz) */
__u32 dclkmin; /* pixelclock lower limit (Hz) */
__u32 dclkmax; /* pixelclock upper limit (Hz) */
unsigned gtf : 1; /* supports GTF */
unsigned dpms : 1; /* supports DPMS */
__u16 gamma; /* Gamma - in fractions of 100 */
__u16 gtf : 1; /* supports GTF */
__u16 misc; /* Misc flags - see FB_MISC_* */
__u8 version; /* EDID version... */
__u8 revision; /* ...and revision */
__u8 max_x; /* Maximum horizontal size (cm) */
__u8 max_y; /* Maximum vertical size (cm) */
};
#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */
......@@ -379,14 +435,19 @@ struct fb_pixmap {
u32 scan_align; /* alignment per scanline */
u32 access_align; /* alignment per read/write */
u32 flags; /* see FB_PIXMAP_* */
/* access methods */
/* access methods */
void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size);
u8 (*inbuf) (struct fb_info *info, u8 *addr);
};
/*
* Frame buffer operations
*/
/*
* Frame buffer operations
*
* LOCKING NOTE: those functions must _ALL_ be called with the console
* semaphore held, this is the only suitable locking mecanism we have
* in 2.6. Some may be called at interrupt time at this point though.
*/
struct fb_ops {
/* open/release and usage marking */
......@@ -394,13 +455,16 @@ struct fb_ops {
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
/* For framebuffers with strange non linear layouts */
/* For framebuffers with strange non linear layouts or that do not
* work with normal memory mapped access
*/
ssize_t (*fb_read)(struct file *file, char *buf, size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct file *file, const char *buf, size_t count, loff_t *ppos);
/* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
/* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info);
......@@ -441,15 +505,14 @@ struct fb_ops {
struct fb_info {
int node;
int flags;
int open; /* Has this been open already ? */
#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct fb_cursor cursor; /* Current cursor */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image Hardware Mapper */
struct fb_pixmap sprite; /* Cursor hardware Mapper */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct fb_ops *fbops;
char *screen_base; /* Virtual address */
......@@ -459,6 +522,7 @@ struct fb_info {
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
/* From here on everything is device dependent */
void *par;
};
......@@ -469,12 +533,14 @@ struct fb_info {
#define FBINFO_FLAG_DEFAULT 0
#endif
// This will go away
#if defined(__sparc__)
/* We map all of our framebuffers such that big-endian accesses
* are what we want, so the following is sufficient.
*/
// This will go away
#define fb_readb sbus_readb
#define fb_readw sbus_readw
#define fb_readl sbus_readl
......@@ -485,7 +551,7 @@ struct fb_info {
#define fb_writeq sbus_writeq
#define fb_memset sbus_memset_io
#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__)
#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__)
#define fb_readb __raw_readb
#define fb_readw __raw_readw
......@@ -546,24 +612,32 @@ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
extern void framebuffer_release(struct fb_info *info);
/* drivers/video/fbmon.c */
#define FB_MAXTIMINGS 0
#define FB_VSYNCTIMINGS 1
#define FB_HSYNCTIMINGS 2
#define FB_DCLKTIMINGS 3
#define FB_IGNOREMON 0x100
#define FB_MAXTIMINGS 0
#define FB_VSYNCTIMINGS 1
#define FB_HSYNCTIMINGS 2
#define FB_DCLKTIMINGS 3
#define FB_IGNOREMON 0x100
#define FB_MODE_IS_UNKNOWN 0
#define FB_MODE_IS_DETAILED 1
#define FB_MODE_IS_STANDARD 2
#define FB_MODE_IS_VESA 4
#define FB_MODE_IS_CALCULATED 8
#define FB_MODE_IS_FIRST 16
extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
const struct fb_info *fb_info);
extern int fbmon_dpms(const struct fb_info *fb_info);
extern int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
struct fb_info *info);
extern int fb_validate_mode(struct fb_var_screeninfo *var,
extern int fb_validate_mode(const struct fb_var_screeninfo *var,
struct fb_info *info);
extern int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var);
extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var);
extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs);
extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs);
extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs);
extern struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize);
extern void fb_destroy_modedb(struct fb_videomode *modedb);
extern void show_edid(unsigned char *edid);
/* drivers/video/modedb.c */
#define VESA_MODEDB_SIZE 34
......@@ -578,58 +652,28 @@ extern struct fb_cmap *fb_default_cmap(int len);
extern void fb_invert_cmaps(void);
struct fb_videomode {
const char *name; /* optional */
u32 refresh; /* optional */
u32 xres;
u32 yres;
u32 pixclock;
u32 left_margin;
u32 right_margin;
u32 upper_margin;
u32 lower_margin;
u32 hsync_len;
u32 vsync_len;
u32 sync;
u32 vmode;
const char *name; /* optional */
u32 refresh; /* optional */
u32 xres;
u32 yres;
u32 pixclock;
u32 left_margin;
u32 right_margin;
u32 upper_margin;
u32 lower_margin;
u32 hsync_len;
u32 vsync_len;
u32 sync;
u32 vmode;
u32 flag;
};
#ifdef MODULE
static inline int fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info,
const char *mode_option,
const struct fb_videomode *db,
unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp)
{
extern int __fb_try_mode(struct fb_var_screeninfo *var,
struct fb_info *info,
const struct fb_videomode *mode,
unsigned int bpp);
/*
* FIXME: How to make the compiler optimize vga640x400 away if
* default_mode is non-NULL?
*/
static const struct fb_videomode vga640x400 = {
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
0, FB_VMODE_NONINTERLACED
};
if (!default_mode)
default_mode = &vga640x400;
if (!default_bpp)
default_bpp = 8;
return __fb_try_mode(var, info, default_mode, default_bpp);
}
#else
extern int __init fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info,
const char *mode_option,
const struct fb_videomode *db,
unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp);
#endif
extern int fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info, const char *mode_option,
const struct fb_videomode *db,
unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp);
#endif /* __KERNEL__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment