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
nexedi
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