Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
f31521dd
Commit
f31521dd
authored
Apr 09, 2003
by
James Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[FBDEV] EDID support from OpenFirmware on PPC platoforms and from the BIOS on intel platforms.
parent
32f5ad40
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1089 additions
and
180 deletions
+1089
-180
arch/i386/boot/compressed/misc.c
arch/i386/boot/compressed/misc.c
+2
-0
arch/i386/boot/video.S
arch/i386/boot/video.S
+34
-0
arch/i386/kernel/setup.c
arch/i386/kernel/setup.c
+3
-1
drivers/video/edid.h
drivers/video/edid.h
+138
-0
drivers/video/fbmon.c
drivers/video/fbmon.c
+753
-173
drivers/video/modedb.c
drivers/video/modedb.c
+105
-0
drivers/video/vesafb.c
drivers/video/vesafb.c
+17
-6
include/asm-i386/setup.h
include/asm-i386/setup.h
+1
-0
include/linux/fb.h
include/linux/fb.h
+9
-0
include/video/edid.h
include/video/edid.h
+27
-0
No files found.
arch/i386/boot/compressed/misc.c
View file @
f31521dd
...
...
@@ -12,6 +12,7 @@
#include <linux/linkage.h>
#include <linux/vmalloc.h>
#include <linux/tty.h>
#include <video/edid.h>
#include <asm/io.h>
/*
...
...
@@ -91,6 +92,7 @@ static unsigned char *real_mode; /* Pointer to real-mode data */
#define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))
#endif
#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
#define EDID_INFO (*(struct edid_info *)(real_mode+0x440))
extern
char
input_data
[];
extern
int
input_len
;
...
...
arch/i386/boot/video.S
View file @
f31521dd
...
...
@@ -135,6 +135,7 @@ vid1:
#endif /* CONFIG_VIDEO_RETAIN */
#endif /* CONFIG_VIDEO_SELECT */
call
mode_params
#
Store
mode
parameters
call
store_edid
popw
%
ds
#
Restore
original
DS
ret
...
...
@@ -1887,6 +1888,39 @@ skip10: movb %ah, %al
popw
%
ax
ret
store_edid
:
pushw
%
es
#
just
save
all
registers
pushw
%
ax
pushw
%
bx
pushw
%
cx
pushw
%
dx
pushw
%
di
pushw
%
fs
popw
%
es
movl
$
0x13131313
,
%
eax
#
memset
block
with
0x13
movw
$
32
,
%
cx
movw
$
0x440
,
%
di
cld
rep
stosl
movw
$
0x4f15
,
%
ax
#
do
VBE
/
DDC
movw
$
0x01
,
%
bx
movw
$
0x00
,
%
cx
movw
$
0x01
,
%
dx
movw
$
0x440
,
%
di
int
$
0x10
popw
%
di
#
restore
all
registers
popw
%
dx
popw
%
cx
popw
%
bx
popw
%
ax
popw
%
es
ret
#
VIDEO_SELECT
-
only
variables
mt_end
:
.
word
0
#
End
of
video
mode
table
if
built
edit_buf
:
.
space
6
#
Line
editor
buffer
...
...
arch/i386/kernel/setup.c
View file @
f31521dd
...
...
@@ -37,6 +37,7 @@
#include <linux/console.h>
#include <linux/root_dev.h>
#include <linux/highmem.h>
#include <video/edid.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
#include <asm/edd.h>
...
...
@@ -85,7 +86,7 @@ struct sys_desc_table_struct {
unsigned
short
length
;
unsigned
char
table
[
0
];
};
struct
edid_info
edid_info
;
struct
e820map
e820
;
unsigned
char
aux_device_present
;
...
...
@@ -883,6 +884,7 @@ void __init setup_arch(char **cmdline_p)
ROOT_DEV
=
ORIG_ROOT_DEV
;
drive_info
=
DRIVE_INFO
;
screen_info
=
SCREEN_INFO
;
edid_info
=
EDID_INFO
;
apm_info
.
bios
=
APM_BIOS_INFO
;
saved_videomode
=
VIDEO_MODE
;
printk
(
"Video mode to be used for restore is %lx
\n
"
,
saved_videomode
);
...
...
drivers/video/edid.h
0 → 100644
View file @
f31521dd
/*
* drivers/video/edid.h - EDID/DDC Header
*
* Based on:
* 1. XFree86 4.3.0, edid.h
* Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
*
* 2. John Fremlin <vii@users.sourceforge.net> and
* Ani Joshi <ajoshi@unixbox.com>
*
* DDC is a Trademark of VESA (Video Electronics Standard Association).
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef __EDID_H__
#define __EDID_H__
#define EDID_LENGTH 0x80
#define EDID_HEADER 0x00
#define EDID_HEADER_END 0x07
#define ID_MANUFACTURER_NAME 0x08
#define ID_MANUFACTURER_NAME_END 0x09
#define ID_MODEL 0x0a
#define ID_SERIAL_NUMBER 0x0c
#define MANUFACTURE_WEEK 0x10
#define MANUFACTURE_YEAR 0x11
#define EDID_STRUCT_VERSION 0x12
#define EDID_STRUCT_REVISION 0x13
#define EDID_STRUCT_DISPLAY 0x14
#define DPMS_FLAGS 0x18
#define ESTABLISHED_TIMING_1 0x23
#define ESTABLISHED_TIMING_2 0x24
#define MANUFACTURERS_TIMINGS 0x25
/* standard timings supported */
#define STD_TIMING 8
#define STD_TIMING_DESCRIPTION_SIZE 2
#define STD_TIMING_DESCRIPTIONS_START 0x26
#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
#define DETAILED_TIMING_DESCRIPTION_SIZE 18
#define NO_DETAILED_TIMING_DESCRIPTIONS 4
#define DETAILED_TIMING_DESCRIPTION_1 0x36
#define DETAILED_TIMING_DESCRIPTION_2 0x48
#define DETAILED_TIMING_DESCRIPTION_3 0x5a
#define DETAILED_TIMING_DESCRIPTION_4 0x6c
#define DESCRIPTOR_DATA 5
#define UPPER_NIBBLE( x ) \
(((128|64|32|16) & (x)) >> 4)
#define LOWER_NIBBLE( x ) \
((1|2|4|8) & (x))
#define COMBINE_HI_8LO( hi, lo ) \
( (((unsigned)hi) << 8) | (unsigned)lo )
#define COMBINE_HI_4LO( hi, lo ) \
( (((unsigned)hi) << 4) | (unsigned)lo )
#define PIXEL_CLOCK_LO (unsigned)block[ 0 ]
#define PIXEL_CLOCK_HI (unsigned)block[ 1 ]
#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000)
#define H_ACTIVE_LO (unsigned)block[ 2 ]
#define H_BLANKING_LO (unsigned)block[ 3 ]
#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] )
#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] )
#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
#define V_ACTIVE_LO (unsigned)block[ 5 ]
#define V_BLANKING_LO (unsigned)block[ 6 ]
#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] )
#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] )
#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ]
#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ]
#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2))
#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2)
#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4)
#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6)
#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
#define H_SIZE_LO (unsigned)block[ 12 ]
#define V_SIZE_LO (unsigned)block[ 13 ]
#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] )
#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] )
#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
#define H_BORDER (unsigned)block[ 15 ]
#define V_BORDER (unsigned)block[ 16 ]
#define FLAGS (unsigned)block[ 17 ]
#define INTERLACED (FLAGS&128)
#define SYNC_TYPE (FLAGS&3<<3)
/* bits 4,3 */
#define SYNC_SEPARATE (3<<3)
#define HSYNC_POSITIVE (FLAGS & 4)
#define VSYNC_POSITIVE (FLAGS & 2)
#define V_MIN_RATE block[ 5 ]
#define V_MAX_RATE block[ 6 ]
#define H_MIN_RATE block[ 7 ]
#define H_MAX_RATE block[ 8 ]
#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10)
#define GTF_SUPPORT block[10]
#define DPMS_ACTIVE_OFF (1 << 5)
#define DPMS_SUSPEND (1 << 6)
#define DPMS_STANDBY (1 << 7)
#endif
/* __EDID_H__ */
drivers/video/fbmon.c
View file @
f31521dd
/*
*
linux/drivers/video/fbmon.c
* linux/drivers/video/fbmon.c
*
* Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
* Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
*
* Credits:
*
* The EDID Parser is a conglomeration from the following sources:
*
* 1. SciTech SNAP Graphics Architecture
* Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
*
* 2. XFree86 4.3.0, interpret_edid.c
* Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
*
* 3. John Fremlin <vii@users.sourceforge.net> and
* Ani Joshi <ajoshi@unixbox.com>
*
* Generalized Timing Formula is derived from:
*
* GTF Spreadsheet by Andy Morrish (1/5/97)
* available at http://www.vesa.org
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
...
...
@@ -11,124 +29,32 @@
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/module.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
#ifdef CONFIG_ALL_PPC
#include <linux/pci.h>
#include <asm/prom.h>
#endif
#include <video/edid.h>
#include "edid.h"
/*
* EDID parser
*
* portions of this file were based on the EDID parser by
* John Fremlin <vii@users.sourceforge.net> and Ani Joshi <ajoshi@unixbox.com>
*/
#define EDID_LENGTH 0x80
#define EDID_HEADER 0x00
#define EDID_HEADER_END 0x07
#define ID_MANUFACTURER_NAME 0x08
#define ID_MANUFACTURER_NAME_END 0x09
#define ID_MODEL 0x0a
#define ID_SERIAL_NUMBER 0x0c
#define MANUFACTURE_WEEK 0x10
#define MANUFACTURE_YEAR 0x11
#define EDID_STRUCT_VERSION 0x12
#define EDID_STRUCT_REVISION 0x13
#define DPMS_FLAGS 0x18
#define ESTABLISHED_TIMING_1 0x23
#define ESTABLISHED_TIMING_2 0x24
#define MANUFACTURERS_TIMINGS 0x25
#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
#define DETAILED_TIMING_DESCRIPTION_SIZE 18
#define NO_DETAILED_TIMING_DESCRIPTIONS 4
#define DETAILED_TIMING_DESCRIPTION_1 0x36
#define DETAILED_TIMING_DESCRIPTION_2 0x48
#define DETAILED_TIMING_DESCRIPTION_3 0x5a
#define DETAILED_TIMING_DESCRIPTION_4 0x6c
#define DESCRIPTOR_DATA 5
#define UPPER_NIBBLE( x ) \
(((128|64|32|16) & (x)) >> 4)
#define LOWER_NIBBLE( x ) \
((1|2|4|8) & (x))
#define COMBINE_HI_8LO( hi, lo ) \
( (((unsigned)hi) << 8) | (unsigned)lo )
#define COMBINE_HI_4LO( hi, lo ) \
( (((unsigned)hi) << 4) | (unsigned)lo )
#define PIXEL_CLOCK_LO (unsigned)block[ 0 ]
#define PIXEL_CLOCK_HI (unsigned)block[ 1 ]
#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*1000)
#define H_ACTIVE_LO (unsigned)block[ 2 ]
#define H_BLANKING_LO (unsigned)block[ 3 ]
#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] )
#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] )
#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
#define V_ACTIVE_LO (unsigned)block[ 5 ]
#define V_BLANKING_LO (unsigned)block[ 6 ]
#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] )
#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] )
#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ]
#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ]
#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2))
#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2)
#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4)
#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6)
#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
#define H_SIZE_LO (unsigned)block[ 12 ]
#define V_SIZE_LO (unsigned)block[ 13 ]
#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] )
#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] )
#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
#define H_BORDER (unsigned)block[ 15 ]
#define V_BORDER (unsigned)block[ 16 ]
#define FLAGS (unsigned)block[ 17 ]
#define INTERLACED (FLAGS&128)
#define SYNC_TYPE (FLAGS&3<<3)
/* bits 4,3 */
#define SYNC_SEPARATE (3<<3)
#define HSYNC_POSITIVE (FLAGS & 4)
#define VSYNC_POSITIVE (FLAGS & 2)
const
unsigned
char
edid_v1_header
[]
=
{
0x00
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0x00
};
const
unsigned
char
edid_v1_descriptor_flag
[]
=
{
0x00
,
0x00
};
static
void
copy_string
(
unsigned
char
*
c
,
unsigned
char
*
s
)
{
int
i
;
c
=
c
+
5
;
for
(
i
=
0
;
(
i
<
13
&&
*
c
!=
0x0A
);
i
++
)
*
(
s
++
)
=
*
(
c
++
);
*
s
=
0
;
while
(
i
--
&&
(
*--
s
==
0x20
))
*
s
=
0
;
}
static
int
edid_checksum
(
unsigned
char
*
edid
)
{
unsigned
char
i
,
csum
=
0
;
...
...
@@ -157,138 +83,785 @@ static int edid_check_header(unsigned char *edid)
return
1
;
}
static
char
*
edid_get_vendor
(
unsigned
char
*
block
)
static
void
parse_vendor_block
(
unsigned
char
*
block
)
{
static
char
sign
[
4
];
unsigned
short
h
;
h
=
COMBINE_HI_8LO
(
block
[
0
],
block
[
1
]);
sign
[
0
]
=
((
h
>>
10
)
&
0x1f
)
+
'A'
-
1
;
sign
[
1
]
=
((
h
>>
5
)
&
0x1f
)
+
'A'
-
1
;
sign
[
2
]
=
(
h
&
0x1f
)
+
'A'
-
1
;
sign
[
3
]
=
0
;
return
sign
;
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
]);
}
static
char
*
edid_get_monitor
(
unsigned
char
*
block
)
static
void
parse_dpms_capabilities
(
unsigned
char
flags
)
{
printk
(
" 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
char
name
[
13
];
unsigned
i
;
const
unsigned
char
*
ptr
=
block
+
DESCRIPTOR_DATA
;
int
tmp
;
/* Chromaticity data */
printk
(
" Chromaticity: "
);
tmp
=
((
block
[
5
]
&
(
3
<<
6
))
>>
6
)
|
(
block
[
0x7
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
"RedX: 0.%03d "
,
tmp
/
1024
);
tmp
=
((
block
[
5
]
&
(
3
<<
4
))
>>
4
)
|
(
block
[
0x8
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
"RedY: 0.%03d
\n
"
,
tmp
/
1024
);
tmp
=
((
block
[
5
]
&
(
3
<<
2
))
>>
2
)
|
(
block
[
0x9
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
" GreenX: 0.%03d "
,
tmp
/
1024
);
tmp
=
(
block
[
5
]
&
3
)
|
(
block
[
0xa
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
"GreenY: 0.%03d
\n
"
,
tmp
/
1024
);
tmp
=
((
block
[
6
]
&
(
3
<<
6
))
>>
6
)
|
(
block
[
0xb
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
" BlueX: 0.%03d "
,
tmp
/
1024
);
tmp
=
((
block
[
6
]
&
(
3
<<
4
))
>>
4
)
|
(
block
[
0xc
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
"BlueY: 0.%03d
\n
"
,
tmp
/
1024
);
tmp
=
((
block
[
6
]
&
(
3
<<
2
))
>>
2
)
|
(
block
[
0xd
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
" WhiteX: 0.%03d "
,
tmp
/
1024
);
tmp
=
(
block
[
6
]
&
3
)
|
(
block
[
0xe
]
<<
2
);
tmp
*=
1000
;
tmp
+=
512
;
printk
(
"WhiteY: 0.%03d
\n
"
,
tmp
/
1024
);
}
for
(
i
=
0
;
i
<
13
;
i
++
,
ptr
++
)
{
if
(
*
ptr
==
0xa
)
{
name
[
i
]
=
0x00
;
return
name
;
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"
);
}
name
[
i
]
=
*
ptr
;
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
;
}
return
name
;
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
))
if
((
block
[
0
]
!=
0x00
)
||
(
block
[
1
]
!=
0x00
)
||
(
block
[
2
]
!=
0x00
)
||
(
block
[
4
]
!=
0x00
))
return
1
;
else
return
0
;
}
static
int
edid_is_serial_block
(
unsigned
char
*
block
)
{
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
2
]
==
0x00
)
&&
(
block
[
3
]
==
0xff
)
&&
(
block
[
4
]
==
0x00
))
return
1
;
else
return
0
;
}
static
int
edid_is_ascii_block
(
unsigned
char
*
block
)
{
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
2
]
==
0x00
)
&&
(
block
[
3
]
==
0xfe
)
&&
(
block
[
4
]
==
0x00
))
return
1
;
else
return
0
;
}
static
int
edid_is_limits_block
(
unsigned
char
*
block
)
{
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
2
]
==
0x00
)
&&
(
block
[
3
]
==
0xfd
)
&&
(
block
[
4
]
==
0x00
))
return
1
;
else
return
0
;
}
static
int
edid_is_monitor_block
(
unsigned
char
*
block
)
{
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
3
]
==
0xfc
))
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
2
]
==
0x00
)
&&
(
block
[
3
]
==
0xfc
)
&&
(
block
[
4
]
==
0x00
))
return
1
;
else
return
0
;
}
static
void
parse_timing_block
(
unsigned
char
*
block
,
struct
fb_var_screeninfo
*
var
)
static
int
edid_is_color_block
(
unsigned
char
*
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
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
2
]
==
0x00
)
&&
(
block
[
3
]
==
0xfb
)
&&
(
block
[
4
]
==
0x00
))
return
1
;
else
return
0
;
}
if
(
HSYNC_POSITIVE
)
var
->
sync
|=
FB_SYNC_HOR_HIGH_ACT
;
if
(
VSYNC_POSITIVE
)
var
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
;
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
)
{
unsigned
char
*
block
,
*
vendor
,
*
monitor
=
NULL
;
int
i
;
unsigned
char
*
block
;
if
(
edid
==
NULL
||
var
==
NULL
)
return
1
;
if
(
!
(
edid_checksum
(
edid
)))
return
0
;
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
;
struct
fb_info
info
;
var
.
xres
=
xres
;
var
.
yres
=
yres
;
fb_get_mode
(
FB_VSYNCTIMINGS
|
FB_IGNOREMON
,
refresh
,
&
var
,
&
info
);
mode
->
xres
=
xres
;
mode
->
yres
=
yres
;
mode
->
pixclock
=
var
.
pixclock
;
mode
->
refresh
=
refresh
;
mode
->
left_margin
=
var
.
left_margin
;
mode
->
right_margin
=
var
.
right_margin
;
mode
->
upper_margin
=
var
.
upper_margin
;
mode
->
lower_margin
=
var
.
lower_margin
;
mode
->
hsync_len
=
var
.
hsync_len
;
mode
->
vsync_len
=
var
.
vsync_len
;
mode
->
vmode
=
0
;
mode
->
sync
=
0
;
}
static
int
get_est_timing
(
unsigned
char
*
block
,
struct
fb_videomode
*
mode
)
{
int
num
=
0
;
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
)
mode
[
num
++
]
=
vesa_modes
[
3
];
if
(
c
&
0x10
)
calc_mode_timings
(
640
,
480
,
67
,
&
mode
[
num
++
]);
if
(
c
&
0x08
)
mode
[
num
++
]
=
vesa_modes
[
4
];
if
(
c
&
0x04
)
mode
[
num
++
]
=
vesa_modes
[
5
];
if
(
c
&
0x02
)
mode
[
num
++
]
=
vesa_modes
[
7
];
if
(
c
&
0x01
)
mode
[
num
++
]
=
vesa_modes
[
8
];
c
=
block
[
1
];
if
(
c
&
0x80
)
mode
[
num
++
]
=
vesa_modes
[
9
];
if
(
c
&
0x40
)
mode
[
num
++
]
=
vesa_modes
[
10
];
if
(
c
&
0x20
)
calc_mode_timings
(
832
,
624
,
75
,
&
mode
[
num
++
]);
if
(
c
&
0x10
)
mode
[
num
++
]
=
vesa_modes
[
12
];
if
(
c
&
0x08
)
mode
[
num
++
]
=
vesa_modes
[
13
];
if
(
c
&
0x04
)
mode
[
num
++
]
=
vesa_modes
[
14
];
if
(
c
&
0x02
)
mode
[
num
++
]
=
vesa_modes
[
15
];
if
(
c
&
0x01
)
mode
[
num
++
]
=
vesa_modes
[
21
];
c
=
block
[
2
];
if
(
c
&
0x80
)
mode
[
num
++
]
=
vesa_modes
[
17
];
return
num
;
}
static
int
get_std_timing
(
unsigned
char
*
block
,
struct
fb_videomode
*
mode
)
{
int
xres
,
yres
=
0
,
refresh
,
ratio
,
i
;
xres
=
(
block
[
0
]
+
31
)
*
8
;
if
(
xres
<=
256
)
return
0
;
printk
(
"EDID ver %d rev %d
\n
"
,
(
int
)
edid
[
EDID_STRUCT_VERSION
],
(
int
)
edid
[
EDID_STRUCT_REVISION
]);
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
;
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
;
}
}
return
1
;
}
vendor
=
edid_get_vendor
(
edid
+
ID_MANUFACTURER_NAME
);
static
int
get_dst_timing
(
unsigned
char
*
block
,
struct
fb_videomode
*
mode
)
{
int
j
,
num
=
0
;
block
=
edid
+
DETAILED_TIMING_DESCRIPTIONS_START
;
for
(
j
=
0
;
j
<
6
;
j
++
,
block
+=
STD_TIMING_DESCRIPTION_SIZE
)
num
+=
get_std_timing
(
block
,
&
mode
[
num
]);
for
(
i
=
0
;
i
<
4
;
i
++
,
block
+=
DETAILED_TIMING_DESCRIPTION_SIZE
)
{
if
(
edid_is_monitor_block
(
block
))
{
monitor
=
edid_get_monitor
(
block
);
return
num
;
}
static
void
get_detailed_timing
(
unsigned
char
*
block
,
struct
fb_videomode
*
mode
)
{
mode
->
xres
=
H_ACTIVE
;
mode
->
yres
=
V_ACTIVE
;
mode
->
pixclock
=
PIXEL_CLOCK
;
mode
->
pixclock
/=
1000
;
mode
->
pixclock
=
KHZ2PICOS
(
mode
->
pixclock
);
mode
->
right_margin
=
H_SYNC_OFFSET
;
mode
->
left_margin
=
(
H_ACTIVE
+
H_BLANKING
)
-
(
H_ACTIVE
+
H_SYNC_OFFSET
+
H_SYNC_WIDTH
);
mode
->
upper_margin
=
V_BLANKING
-
V_SYNC_OFFSET
-
V_SYNC_WIDTH
;
mode
->
lower_margin
=
V_SYNC_OFFSET
;
mode
->
hsync_len
=
H_SYNC_WIDTH
;
mode
->
vsync_len
=
V_SYNC_WIDTH
;
if
(
HSYNC_POSITIVE
)
mode
->
sync
|=
FB_SYNC_HOR_HIGH_ACT
;
if
(
VSYNC_POSITIVE
)
mode
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
;
mode
->
refresh
=
PIXEL_CLOCK
/
((
H_ACTIVE
+
H_BLANKING
)
*
(
V_ACTIVE
+
V_BLANKING
));
mode
->
vmode
=
0
;
}
/**
* fb_create_modedb - create video mode database
* @edid: EDID data
* @dbsize: database size
*
* RETURNS: struct fb_videomode, @dbsize contains length of database
*
* DESCRIPTION:
* This function builds a mode database using the contents of the EDID
* data
*/
struct
fb_videomode
*
fb_create_modedb
(
unsigned
char
*
edid
,
int
*
dbsize
)
{
struct
fb_videomode
*
mode
,
*
m
;
unsigned
char
*
block
;
int
num
=
0
,
i
;
mode
=
kmalloc
(
50
*
sizeof
(
struct
fb_videomode
),
GFP_KERNEL
);
if
(
mode
==
NULL
)
return
NULL
;
memset
(
mode
,
0
,
50
*
sizeof
(
struct
fb_videomode
));
if
(
edid
==
NULL
||
!
edid_checksum
(
edid
)
||
!
edid_check_header
(
edid
))
{
kfree
(
mode
);
return
NULL
;
}
*
dbsize
=
0
;
block
=
edid
+
ESTABLISHED_TIMING_1
;
num
+=
get_est_timing
(
block
,
&
mode
[
num
]);
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
]);
block
=
edid
+
DETAILED_TIMING_DESCRIPTIONS_START
;
for
(
i
=
0
;
i
<
4
;
i
++
,
block
+=
DETAILED_TIMING_DESCRIPTION_SIZE
)
{
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
]);
num
++
;
}
}
/* Yikes, EDID data is totally useless */
if
(
!
num
)
{
kfree
(
mode
);
return
NULL
;
}
*
dbsize
=
num
;
m
=
kmalloc
(
num
*
sizeof
(
struct
fb_videomode
),
GFP_KERNEL
);
if
(
!
m
)
return
mode
;
memmove
(
m
,
mode
,
num
*
sizeof
(
struct
fb_videomode
));
kfree
(
mode
);
return
m
;
}
/**
* fb_destroy_modedb - destroys mode database
* @modedb: mode database to destroy
*
* DESCRIPTION:
* Destroy mode database created by fb_create_modedb
*/
void
fb_destroy_modedb
(
struct
fb_videomode
*
modedb
)
{
if
(
modedb
)
kfree
(
modedb
);
}
printk
(
"EDID: detected %s %s
\n
"
,
vendor
,
monitor
);
/**
* 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: "
);
for
(
i
=
0
;
i
<
4
;
i
++
,
block
+=
DETAILED_TIMING_DESCRIPTION_SIZE
)
{
if
(
edid_is_timing_block
(
block
))
{
parse_timing_block
(
block
,
var
);
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
->
gtf
=
(
GTF_SUPPORT
)
?
1
:
0
;
specs
->
dpms
=
edid
[
DPMS_FLAGS
];
retval
=
0
;
printk
(
"From EDID
\n
"
);
break
;
}
}
return
1
;
/* estimate monitor limits based on modes supported */
if
(
retval
)
{
struct
fb_videomode
*
modes
;
int
num_modes
,
i
,
hz
,
hscan
,
pixclock
;
modes
=
fb_create_modedb
(
edid
,
&
num_modes
);
if
(
!
modes
)
{
printk
(
"None Available
\n
"
);
return
1
;
}
retval
=
0
;
for
(
i
=
0
;
i
<
num_modes
;
i
++
)
{
hz
=
modes
[
i
].
refresh
;
pixclock
=
PICOS2KHZ
(
modes
[
i
].
pixclock
)
*
1000
;
hscan
=
(
modes
[
i
].
yres
*
105
*
hz
+
5000
)
/
100
;
if
(
specs
->
dclkmax
==
0
||
specs
->
dclkmax
<
pixclock
)
specs
->
dclkmax
=
pixclock
;
if
(
specs
->
dclkmin
==
0
||
specs
->
dclkmin
>
pixclock
)
specs
->
dclkmin
=
pixclock
;
if
(
specs
->
hfmax
==
0
||
specs
->
hfmax
<
hscan
)
specs
->
hfmax
=
hscan
;
if
(
specs
->
hfmin
==
0
||
specs
->
hfmin
>
hscan
)
specs
->
hfmin
=
hscan
;
if
(
specs
->
vfmax
==
0
||
specs
->
vfmax
<
hz
)
specs
->
vfmax
=
hz
;
if
(
specs
->
vfmin
==
0
||
specs
->
vfmin
>
hz
)
specs
->
vfmin
=
hz
;
}
printk
(
"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
);
return
retval
;
}
#ifdef CONFIG_PCI
char
*
get_EDID
(
struct
pci_dev
*
pdev
)
void
show_edid
(
unsigned
char
*
edid
)
{
unsigned
char
*
block
;
int
i
;
if
(
edid
==
NULL
)
return
;
if
(
!
(
edid_checksum
(
edid
)))
return
;
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
);
printk
(
" Display Characteristics:
\n
"
);
parse_display_block
(
edid
+
EDID_STRUCT_DISPLAY
);
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
);
printk
(
" Supported VESA Modes
\n
"
);
parse_std_md_block
(
edid
+
ESTABLISHED_TIMING_1
);
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
);
}
else
if
(
edid_is_ascii_block
(
block
))
{
parse_ascii_block
(
block
);
}
else
if
(
edid_is_limits_block
(
block
))
{
parse_limits_block
(
block
);
}
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
);
}
}
printk
(
"========================================
\n
"
);
}
#ifdef CONFIG_ALL_PPC
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
;
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
);
pedid
=
(
unsigned
char
*
)
get_property
(
dp
,
propnames
[
i
],
NULL
);
if
(
pedid
!=
NULL
)
return
pedid
;
}
dp
=
dp
->
child
;
}
show_edid
(
pedid
);
return
pedid
;
#else
return
NULL
;
}
#endif
#ifdef CONFIG_X86
char
*
get_EDID_from_BIOS
(
void
*
dummy
)
{
unsigned
char
*
pedid
=
edid_info
.
dummy
;
if
(
!
pedid
)
return
NULL
;
show_edid
(
pedid
);
return
pedid
;
}
#endif
...
...
@@ -679,8 +1252,15 @@ int fb_validate_mode(struct fb_var_screeninfo *var, struct fb_info *info)
}
EXPORT_SYMBOL
(
parse_edid
);
#ifdef CONFIG_PCI
EXPORT_SYMBOL
(
get_EDID
);
EXPORT_SYMBOL
(
show_edid
);
#ifdef CONFIG_X86
EXPORT_SYMBOL
(
get_EDID_from_BIOS
);
#endif
#ifdef CONFIG_ALL_PPC
EXPORT_SYMBOL
(
get_EDID_from_OF
);
#endif
EXPORT_SYMBOL
(
fb_get_monitor_limits
);
EXPORT_SYMBOL
(
fb_get_mode
);
EXPORT_SYMBOL
(
fb_validate_mode
);
EXPORT_SYMBOL
(
fb_create_modedb
);
EXPORT_SYMBOL
(
fb_destroy_modedb
);
drivers/video/modedb.c
View file @
f31521dd
...
...
@@ -251,6 +251,110 @@ 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
},
/* 1 640x400-85 VESA */
{
NULL
,
85
,
640
,
400
,
31746
,
96
,
32
,
41
,
01
,
64
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 2 720x400-85 VESA */
{
NULL
,
85
,
721
,
400
,
28169
,
108
,
36
,
42
,
01
,
72
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 3 640x480-60 VESA */
{
NULL
,
60
,
640
,
480
,
39682
,
48
,
16
,
33
,
10
,
96
,
2
,
0
,
FB_VMODE_NONINTERLACED
},
/* 4 640x480-72 VESA */
{
NULL
,
72
,
640
,
480
,
31746
,
128
,
24
,
29
,
9
,
40
,
2
,
0
,
FB_VMODE_NONINTERLACED
},
/* 5 640x480-75 VESA */
{
NULL
,
75
,
640
,
480
,
31746
,
120
,
16
,
16
,
01
,
64
,
3
,
0
,
FB_VMODE_NONINTERLACED
},
/* 6 640x480-85 VESA */
{
NULL
,
85
,
640
,
480
,
27777
,
80
,
56
,
25
,
01
,
56
,
3
,
0
,
FB_VMODE_NONINTERLACED
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 13 1024x768-60 VESA */
{
NULL
,
60
,
1024
,
768
,
15384
,
160
,
24
,
29
,
3
,
136
,
6
,
0
,
FB_VMODE_NONINTERLACED
},
/* 14 1024x768-70 VESA */
{
NULL
,
70
,
1024
,
768
,
13333
,
144
,
24
,
29
,
3
,
136
,
6
,
0
,
FB_VMODE_NONINTERLACED
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 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
},
/* 28 1792x1344-60 VESA */
{
NULL
,
60
,
1792
,
1344
,
4882
,
328
,
128
,
46
,
1
,
200
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 29 1792x1344-75 VESA */
{
NULL
,
75
,
1792
,
1344
,
3831
,
352
,
96
,
69
,
1
,
216
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 30 1856x1392-60 VESA */
{
NULL
,
60
,
1856
,
1392
,
4580
,
352
,
96
,
43
,
1
,
224
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 31 1856x1392-75 VESA */
{
NULL
,
75
,
1856
,
1392
,
3472
,
352
,
128
,
104
,
1
,
224
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 32 1920x1440-60 VESA */
{
NULL
,
60
,
1920
,
1440
,
4273
,
344
,
128
,
56
,
1
,
200
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
/* 33 1920x1440-75 VESA */
{
NULL
,
60
,
1920
,
1440
,
3367
,
352
,
144
,
56
,
1
,
224
,
3
,
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
},
};
static
int
__init
my_atoi
(
const
char
*
name
)
{
...
...
@@ -432,3 +536,4 @@ int __init fb_find_mode(struct fb_var_screeninfo *var,
}
EXPORT_SYMBOL
(
__fb_try_mode
);
EXPORT_SYMBOL
(
vesa_modes
);
drivers/video/vesafb.c
View file @
f31521dd
...
...
@@ -19,7 +19,9 @@
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#ifdef __i386__
#include <video/edid.h>
#endif
#include <asm/io.h>
#include <asm/mtrr.h>
...
...
@@ -213,6 +215,7 @@ int __init vesafb_setup(char *options)
int
__init
vesafb_init
(
void
)
{
int
video_cmap_len
;
char
*
edid
=
0
;
int
i
;
if
(
screen_info
.
orig_video_isVGA
!=
VIDEO_TYPE_VLFB
)
...
...
@@ -296,12 +299,20 @@ int __init vesafb_init(void)
vesafb_defined
.
yres_virtual
=
vesafb_defined
.
yres
;
ypan
=
0
;
}
/* some dummy values for timing to make fbset happy */
vesafb_defined
.
pixclock
=
10000000
/
vesafb_defined
.
xres
*
1000
/
vesafb_defined
.
yres
;
vesafb_defined
.
left_margin
=
(
vesafb_defined
.
xres
/
8
)
&
0xf8
;
vesafb_defined
.
hsync_len
=
(
vesafb_defined
.
xres
/
8
)
&
0xf8
;
#ifdef __i386__
edid
=
get_EDID_from_BIOS
(
0
);
if
(
edid
)
parse_edid
(
edid
,
&
vesafb_defined
);
else
#endif
{
/* some dummy values for timing to make fbset happy */
vesafb_defined
.
pixclock
=
10000000
/
vesafb_defined
.
xres
*
1000
/
vesafb_defined
.
yres
;
vesafb_defined
.
left_margin
=
(
vesafb_defined
.
xres
/
8
)
&
0xf8
;
vesafb_defined
.
hsync_len
=
(
vesafb_defined
.
xres
/
8
)
&
0xf8
;
}
if
(
vesafb_defined
.
bits_per_pixel
>
8
)
{
vesafb_defined
.
red
.
offset
=
screen_info
.
red_pos
;
vesafb_defined
.
red
.
length
=
screen_info
.
red_size
;
...
...
include/asm-i386/setup.h
View file @
f31521dd
...
...
@@ -37,6 +37,7 @@
#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
#define EDID_INFO (*(struct edid_info *) (PARAM+0x440))
#define EDD_NR (*(unsigned char *) (PARAM+EDDNR))
#define EDD_BUF ((struct edd_info *) (PARAM+EDDBUF))
#define COMMAND_LINE ((char *) (PARAM+2048))
...
...
include/linux/fb.h
View file @
f31521dd
...
...
@@ -504,6 +504,15 @@ 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
,
struct
fb_info
*
info
);
extern
int
parse_edid
(
unsigned
char
*
edid
,
struct
fb_var_screeninfo
*
var
);
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
extern
const
struct
fb_videomode
vesa_modes
[];
/* drivers/video/fbcmap.c */
extern
int
fb_alloc_cmap
(
struct
fb_cmap
*
cmap
,
int
len
,
int
transp
);
...
...
include/video/edid.h
0 → 100644
View file @
f31521dd
#ifndef __linux_video_edid_h__
#define __linux_video_edid_h__
#ifdef __KERNEL__
#include <linux/config.h>
#ifdef CONFIG_ALL_PPC
#include <linux/pci.h>
#endif
#ifdef CONFIG_X86
struct
edid_info
{
unsigned
char
dummy
[
128
];
};
extern
struct
edid_info
edid_info
;
extern
char
*
get_EDID_from_BIOS
(
void
*
);
#endif
/* CONFIG_X86 */
#ifdef CONFIG_ALL_PPC
extern
char
*
get_EDID_from_OF
(
struct
pci_dev
*
pdev
);
#endif
#endif
/* __KERNEL__ */
#endif
/* __linux_video_edid_h__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment