* Re: [PATCH]: EDID parser
@ 2003-04-03 16:38 Petr Vandrovec
2003-04-03 17:15 ` Sven Luther
0 siblings, 1 reply; 8+ messages in thread
From: Petr Vandrovec @ 2003-04-03 16:38 UTC (permalink / raw)
To: Sven Luther; +Cc: James Simmons, Linux Fbdev development list
On 3 Apr 03 at 18:21, Sven Luther wrote:
> On Thu, Apr 03, 2003 at 04:21:14PM +0100, Alan Cox wrote:
> > On Iau, 2003-04-03 at 15:15, Sven Luther wrote:
> > > > Read is not enough. If you have connected one /dev/fbx to two
> > > > monitors, you must find highest common denominator for them, and use
> > > > this one.
> > >
> > > Err, i don't understand this ? Do you mean you are outputing to two
> > > monitors at the same time ?
Yes. With matroxfb you can output same signal to all three outputs.
It is default if you have g450 or g550 with recent driver.
> > > If that is so maybe you mean, speaking in graphic card terminology, and
> > > not in fbdev one, that you are sharing one common framebuffer between
> > > two outputs, right, possibly doing mirroring tricks or something such ?
> >
> > Classic example is a SiS 6326 driving monitor and TV. You need to keep the
> > display to TV acceptable ranges.
>
> You mean, driving both display with the same ramdac ?
See http://www.bglug.ca/matrox_tvout/g450.jpg. Two inputs, three outputs,
and almost any possible connection between them.
Petr Vandrovec
vandrove@vc.cvut.cz
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH]: EDID parser
2003-04-03 16:38 [PATCH]: EDID parser Petr Vandrovec
@ 2003-04-03 17:15 ` Sven Luther
0 siblings, 0 replies; 8+ messages in thread
From: Sven Luther @ 2003-04-03 17:15 UTC (permalink / raw)
To: Petr Vandrovec; +Cc: Sven Luther, James Simmons, Linux Fbdev development list
On Thu, Apr 03, 2003 at 06:38:44PM +0200, Petr Vandrovec wrote:
> On 3 Apr 03 at 18:21, Sven Luther wrote:
> > On Thu, Apr 03, 2003 at 04:21:14PM +0100, Alan Cox wrote:
> > > On Iau, 2003-04-03 at 15:15, Sven Luther wrote:
> > > > > Read is not enough. If you have connected one /dev/fbx to two
> > > > > monitors, you must find highest common denominator for them, and use
> > > > > this one.
> > > >
> > > > Err, i don't understand this ? Do you mean you are outputing to two
> > > > monitors at the same time ?
>
> Yes. With matroxfb you can output same signal to all three outputs.
> It is default if you have g450 or g550 with recent driver.
>
> > > > If that is so maybe you mean, speaking in graphic card terminology, and
> > > > not in fbdev one, that you are sharing one common framebuffer between
> > > > two outputs, right, possibly doing mirroring tricks or something such ?
> > >
> > > Classic example is a SiS 6326 driving monitor and TV. You need to keep the
> > > display to TV acceptable ranges.
> >
> > You mean, driving both display with the same ramdac ?
>
> See http://www.bglug.ca/matrox_tvout/g450.jpg. Two inputs, three outputs,
> and almost any possible connection between them.
A, ok, you have the CRTC for which you program the timings and such, and
which can then be connected to the DACS or the TMDS or the video output.
You would need to keep a CRTC to output mapping in this case, and read
the DDC buses on the output, fill a table or something, and when the
user change the output mapping, revalidate the video modes in accord to
that. The mapping would not be a bijective one, but you could have more
than one output for one CRTC, i don't think you can have more than one
CRTC for a given output though. You could simply maintain a list of
outputs for each CRTC, and when you need to validate the mode, you have
to validate it for every output linked to each CRTC.
Friendly,
Sven Luther
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Linux-fbdev-devel] [PATCH]: EDID parser
@ 2003-04-03 15:21 Alan Cox
2003-04-03 16:33 ` Geert Uytterhoeven
0 siblings, 1 reply; 8+ messages in thread
From: Alan Cox @ 2003-04-03 15:21 UTC (permalink / raw)
To: Sven Luther
Cc: Petr Vandrovec, James Simmons, Linux Fbdev development list,
Linux Kernel Mailing List
On Iau, 2003-04-03 at 15:15, Sven Luther wrote:
> > Read is not enough. If you have connected one /dev/fbx to two monitors,
> > you must find highest common denominator for them, and use this one.
>
> Err, i don't understand this ? Do you mean you are outputing to two
> monitors at the same time ?
I think you mean lowest common denominator.
> If that is so maybe you mean, speaking in graphic card terminology, and
> not in fbdev one, that you are sharing one common framebuffer between
> two outputs, right, possibly doing mirroring tricks or something such ?
Classic example is a SiS 6326 driving monitor and TV. You need to keep
the display to TV acceptable ranges.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH]: EDID parser
2003-04-03 15:21 [Linux-fbdev-devel] " Alan Cox
@ 2003-04-03 16:33 ` Geert Uytterhoeven
2003-04-03 17:10 ` [Linux-fbdev-devel] " Sven Luther
0 siblings, 1 reply; 8+ messages in thread
From: Geert Uytterhoeven @ 2003-04-03 16:33 UTC (permalink / raw)
To: Alan Cox
Cc: Sven Luther, Petr Vandrovec, James Simmons,
Linux Fbdev development list, Linux Kernel Mailing List
On 3 Apr 2003, Alan Cox wrote:
> On Iau, 2003-04-03 at 15:15, Sven Luther wrote:
> > > Read is not enough. If you have connected one /dev/fbx to two monitors,
> > > you must find highest common denominator for them, and use this one.
> >
> > Err, i don't understand this ? Do you mean you are outputing to two
> > monitors at the same time ?
>
> I think you mean lowest common denominator.
>
> > If that is so maybe you mean, speaking in graphic card terminology, and
> > not in fbdev one, that you are sharing one common framebuffer between
> > two outputs, right, possibly doing mirroring tricks or something such ?
>
> Classic example is a SiS 6326 driving monitor and TV. You need to keep
> the display to TV acceptable ranges.
I don't know whether that's a good example...
I assume the signal for the TV is different from the signal for the monitor
(these days you don't find many monitors that do 15.6 kHz / 50 Hz)? In that
case it's just the resolution that has to be more or less compatible.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [Linux-fbdev-devel] [PATCH]: EDID parser
2003-04-03 16:33 ` Geert Uytterhoeven
@ 2003-04-03 17:10 ` Sven Luther
2003-04-03 16:15 ` Alan Cox
0 siblings, 1 reply; 8+ messages in thread
From: Sven Luther @ 2003-04-03 17:10 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Alan Cox, Sven Luther, Petr Vandrovec, James Simmons,
Linux Fbdev development list, Linux Kernel Mailing List
On Thu, Apr 03, 2003 at 06:33:17PM +0200, Geert Uytterhoeven wrote:
> On 3 Apr 2003, Alan Cox wrote:
> > On Iau, 2003-04-03 at 15:15, Sven Luther wrote:
> > > > Read is not enough. If you have connected one /dev/fbx to two monitors,
> > > > you must find highest common denominator for them, and use this one.
> > >
> > > Err, i don't understand this ? Do you mean you are outputing to two
> > > monitors at the same time ?
> >
> > I think you mean lowest common denominator.
> >
> > > If that is so maybe you mean, speaking in graphic card terminology, and
> > > not in fbdev one, that you are sharing one common framebuffer between
> > > two outputs, right, possibly doing mirroring tricks or something such ?
> >
> > Classic example is a SiS 6326 driving monitor and TV. You need to keep
> > the display to TV acceptable ranges.
>
> I don't know whether that's a good example...
Ok, i will take the card i am currently working on for XFree86 as an
example, and you (Alan and Petr mostly) will tell me if this is a common
case, or if i miss something.
It has two outputs, where i can hook either a DVI or a VGA monitor. Each
of these video outputs correspond to a viewport, and there is hardware
which will let you set the output timings and the dot clock. You also
have to configure which part of the framebuffer you are reading, and
eventually setup a scaller to scale the pixels you read to the correct
output buffer. You also have for each head a DDC/I2C bus you can use to
speak with the monitor.
On the other side, you have the framebuffer area, which you can split in
two or not, and is fully independent from the above head issues.
So you could either have one fbdev and two viewports inside it, or have
two separate viewports each with only one viewport.
What i am trying to implement for the XFree86 driver is to have a common
framebuffer, so the graphic engine can be shared between them without
further changes, enabling dual head DRI suppport for example. Sure i
have a 8K coordinates range which makes this easy, but maybe other cards
have more strenous limits there.
Now, the plan is to separate the setup stuff that is common to the
_chip_ from the setup stuff that is specific to each _head_ or output.
In this case, it becomes easy to have the DDC port being specific to
each head, and this would sole all problems, since you would read all
the monitors attached to all the DDC buses, store them somewhere (and
ask again at the user demand, like Benjamin suggested), and when the
user changes the head mapping, or at head mapping initialization, have
the mode being validated against the monitors we _know_ are attached to
each DDC bus.
Now, i know that some boards have more DDC buses than heads or maybe
ramdacs, and things can be a bit more complicated. What do you say Petr ?
Could you yell us more about the matrox internal design with regard to
this ?
Friendly,
Sven Luther
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH]: EDID parser
2003-04-03 17:10 ` [Linux-fbdev-devel] " Sven Luther
@ 2003-04-03 16:15 ` Alan Cox
2003-04-03 17:18 ` Sven Luther
0 siblings, 1 reply; 8+ messages in thread
From: Alan Cox @ 2003-04-03 16:15 UTC (permalink / raw)
To: Sven Luther
Cc: Geert Uytterhoeven, Petr Vandrovec, James Simmons,
Linux Fbdev development list, Linux Kernel Mailing List
On Iau, 2003-04-03 at 18:10, Sven Luther wrote:
> It has two outputs, where i can hook either a DVI or a VGA monitor. Each
> of these video outputs correspond to a viewport, and there is hardware
> which will let you set the output timings and the dot clock. You also
> have to configure which part of the framebuffer you are reading, and
> eventually setup a scaller to scale the pixels you read to the correct
> output buffer. You also have for each head a DDC/I2C bus you can use to
> speak with the monitor.
Very common except lower end stuff generally has a single frame buffer
that both show and cannot be split or scanned by multiple outputs at
different rates.
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH]: EDID parser
2003-04-03 16:15 ` Alan Cox
@ 2003-04-03 17:18 ` Sven Luther
0 siblings, 0 replies; 8+ messages in thread
From: Sven Luther @ 2003-04-03 17:18 UTC (permalink / raw)
To: Alan Cox
Cc: Sven Luther, Geert Uytterhoeven, Petr Vandrovec, James Simmons,
Linux Fbdev development list, Linux Kernel Mailing List
On Thu, Apr 03, 2003 at 05:15:32PM +0100, Alan Cox wrote:
> On Iau, 2003-04-03 at 18:10, Sven Luther wrote:
> > It has two outputs, where i can hook either a DVI or a VGA monitor. Each
> > of these video outputs correspond to a viewport, and there is hardware
> > which will let you set the output timings and the dot clock. You also
> > have to configure which part of the framebuffer you are reading, and
> > eventually setup a scaller to scale the pixels you read to the correct
> > output buffer. You also have for each head a DDC/I2C bus you can use to
> > speak with the monitor.
>
> Very common except lower end stuff generally has a single frame buffer
> that both show and cannot be split or scanned by multiple outputs at
> different rates.
So, using the terminology of Petr's graph, you have only one CRTC, with
two possible outputs, or maybe you have two CRTC but which needs to be
synchronized between them ?
Friendly,
Sven Luther
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Linux-fbdev-devel] [PATCH]: EDID parser
2003-04-02 15:41 ` Antonino Daplas
@ 2003-04-02 21:55 James Simmons
2003-04-03 0:45 ` Antonino Daplas
-1 siblings, 1 reply; 8+ messages in thread
From: James Simmons @ 2003-04-02 21:55 UTC (permalink / raw)
To: Antonino Daplas
Cc: Linux Fbdev development list, Linux Kernel Mailing List, Petr
> James,
>
> Here's a revised patch. I was able to receive source code from SciTech
> (c/o Kendall Bennett) which allowed me to fix bugs and complete the
> parser. It's probably around 90-95% complete in terms of basic parsing.
>
> It also fixes memory leaks which was present in the old patch.
Let really good. I applied it to my local tree but haven't passed it to BK
fbdev yet. The only thing I like to see changed is get_EDID. At present it
accepts a struct pci_dev. Now for generic support for the intel platform
we can get this from the BIOS. You already have a patch that does this.
It doesn't need a struct pci_dev in this case. It is possible to get this
info from the i2c bus but I never seen any drivers do this. What data would
we have to pass in get the EDID inforamtion? So the question is how
generic will get_EDID end up being or will we have to have driver specfic
hooks since I don't pitcure i2c approaches being the same for each video
card. Petr didn't you attempt this with the matrox driver at one time?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH]: EDID parser
2003-04-02 21:55 [Linux-fbdev-devel] " James Simmons
@ 2003-04-03 0:45 ` Antonino Daplas
0 siblings, 0 replies; 8+ messages in thread
From: Antonino Daplas @ 2003-04-03 0:45 UTC (permalink / raw)
To: James Simmons
Cc: Linux Fbdev development list, Linux Kernel Mailing List,
Petr Vandrovec
On Thu, 2003-04-03 at 05:55, James Simmons wrote:
>
> > James,
> >
> > Here's a revised patch. I was able to receive source code from SciTech
> > (c/o Kendall Bennett) which allowed me to fix bugs and complete the
> > parser. It's probably around 90-95% complete in terms of basic parsing.
> >
> > It also fixes memory leaks which was present in the old patch.
>
> Let really good. I applied it to my local tree but haven't passed it to BK
> fbdev yet. The only thing I like to see changed is get_EDID. At present it
> accepts a struct pci_dev. Now for generic support for the intel platform
> we can get this from the BIOS. You already have a patch that does this.
> It doesn't need a struct pci_dev in this case. It is possible to get this
> info from the i2c bus but I never seen any drivers do this. What data would
> we have to pass in get the EDID inforamtion? So the question is how
> generic will get_EDID end up being or will we have to have driver specfic
> hooks since I don't pitcure i2c approaches being the same for each video
> card. Petr didn't you attempt this with the matrox driver at one time?
>
I think we just need an additional method in struct fb_ops. Something like
this:
unsigned char *fb_get_edid(struct fb_info *info)
{
if (info->fbops->fb_get_edid)
return info->fbops->fb_get_edid(info);
else
return fallback_get_edid_method();
}
We can get the EDID by different methods:
1. User uploads EDID to kernel via an ioctl. This is always preferred,
as it gives the user the power to override machine settings, or if there
is no other method to get the EDID. We can also have a userland utility
that encodes user-specified monitor information and modelines into EDID
info (a reverse EDID parser). For instance, selected entries in
/etc/fb.modes can be easily converted to EDID which the user can upload
to fbdev.
2. Gets it through device-specific hooks (i2c, whatever), if available.
This is second choice, as it can get the EDID anytime. This is useful
when a user decides to change monitors without rebooting, or if the
device is a non-primary display.
3. Some architecture specific methods, such as doing it via the BIOS.
This is the last choice, our fallback method. as this EDID may be static
and represents only the display detected at boot time.
For supplementary functions, we also need some kind of control that
allows the user to tell fbdev "I've switched monitors, please reread the
EDID". We want to avoid doing DDC each time fbdev does an fb_set_var(),
especially for DDC1 which can be very slow.
Also, a way to download the EDID from kernel to userland.
Tony
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH]: EDID parser
@ 2003-04-01 15:32 Antonino Daplas
2003-04-02 15:41 ` Antonino Daplas
0 siblings, 1 reply; 8+ messages in thread
From: Antonino Daplas @ 2003-04-01 15:32 UTC (permalink / raw)
To: James Simmons; +Cc: Linux Fbdev development list
Hi James,
Attached is a diff against 2.5.66. It includes a reasonably complete
EDID parser and also includes some new functions that can be used by
fbdev drivers (for mode selection purposes)
1. fb_create_modedb()
creates a mode database which can be fed to fb_find_mode(). This means
that fb_find_mode() should not be __init anymore.
2. fb_destroy_modedb()
destroy mode database created by fb_create_modedb()
3. fb_get_monitor_limits()
gets monitor operating limits (max and min hscan, max and min refresh,
max pixclock, DPMS and GTF capability)
useful for validating video modes and calculating mode timings (if GTF
capable)
4. show_edid()
just prints EDID data into human-readable format.
All of of the above depends on valid EDID data.
Tony
diff -Naur linux-2.5.66-orig/drivers/video/edid.h linux-2.5.66-fbdev/drivers/video/edid.h
--- linux-2.5.66-orig/drivers/video/edid.h 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.5.66-fbdev/drivers/video/edid.h 2003-04-01 14:30:14.000000000 +0000
@@ -0,0 +1,128 @@
+/*
+ * drivers/video/edid.h - EDID parser definitions
+ *
+ * portions of this file were based on the EDID parser by
+ * John Fremlin <vii@users.sourceforge.net> and Ani Joshi <ajoshi@unixbox.com>
+ */
+
+#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__ */
diff -Naur linux-2.5.66-orig/drivers/video/fbmon.c linux-2.5.66-fbdev/drivers/video/fbmon.c
--- linux-2.5.66-orig/drivers/video/fbmon.c 2003-03-29 12:37:03.000000000 +0000
+++ linux-2.5.66-fbdev/drivers/video/fbmon.c 2003-04-01 15:14:42.000000000 +0000
@@ -11,12 +11,10 @@
#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 <asm/prom.h>
#endif
+#include "edid.h"
/*
* EDID parser
@@ -25,110 +23,21 @@
* 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,37 +66,144 @@
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;
+ unsigned char c[4];
- return sign;
+ 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 parse_display_block(unsigned char *block)
{
- static char name[13];
- unsigned i;
- const unsigned char *ptr = block + DESCRIPTOR_DATA;
+ unsigned char c;
- for (i = 0; i < 13; i++, ptr++) {
- if (*ptr == 0xa) {
- name[i] = 0x00;
- return name;
+ 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 & 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;
+ 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))
@@ -196,6 +212,30 @@
return 1;
}
+static int edid_is_serial_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) && (block[3] == 0xff))
+ return 1;
+ else
+ return 0;
+}
+
+static int edid_is_ascii_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) && (block[3] == 0xfe))
+ return 1;
+ else
+ return 0;
+}
+
+static int edid_is_limits_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) && (block[3] == 0xfd))
+ return 1;
+ else
+ return 0;
+}
+
static int edid_is_monitor_block(unsigned char *block)
{
if ((block[0] == 0x00) && (block[1] == 0x00) && (block[3] == 0xfc))
@@ -204,75 +244,475 @@
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[3] == 0xfb))
+ 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[3] == 0xfa))
+ 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;
- vendor = edid_get_vendor(edid + ID_MANUFACTURER_NAME);
+ 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;
+}
- block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+static int get_dst_timing(unsigned char *block,
+ struct fb_videomode *mode)
+{
+ int j, num = 0;
- for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
- if (edid_is_monitor_block(block)) {
- monitor = edid_get_monitor(block);
+ for (j = 0; j < 5; j++, block+= STD_TIMING_DESCRIPTION_SIZE)
+ num += get_std_timing(block, &mode[num]);
+
+ 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))
+ 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++;
}
}
+
+ if (!num)
+ 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)
+{
+ 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;
+ unsigned char *block;
- printk("EDID: detected %s %s\n", vendor, monitor);
+ 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;
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];
+ return 0;
}
}
return 1;
}
+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_PCI
char *get_EDID(struct pci_dev *pdev)
{
+ unsigned char *pedid = NULL;
#ifdef CONFIG_ALL_PPC
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) {
@@ -285,10 +725,9 @@
}
dp = dp->child;
}
- return pedid;
-#else
- return NULL;
#endif
+ show_edid(pedid);
+ return pedid;
}
#endif
@@ -679,8 +1118,12 @@
}
EXPORT_SYMBOL(parse_edid);
+EXPORT_SYMBOL(show_edid);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(get_EDID);
#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);
diff -Naur linux-2.5.66-orig/drivers/video/modedb.c linux-2.5.66-fbdev/drivers/video/modedb.c
--- linux-2.5.66-orig/drivers/video/modedb.c 2003-03-29 12:37:03.000000000 +0000
+++ linux-2.5.66-fbdev/drivers/video/modedb.c 2003-04-01 14:30:19.000000000 +0000
@@ -251,6 +251,110 @@
},
};
+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 @@
}
EXPORT_SYMBOL(__fb_try_mode);
+EXPORT_SYMBOL(vesa_modes);
diff -Naur linux-2.5.66-orig/include/linux/fb.h linux-2.5.66-fbdev/include/linux/fb.h
--- linux-2.5.66-orig/include/linux/fb.h 2003-03-29 21:09:54.000000000 +0000
+++ linux-2.5.66-fbdev/include/linux/fb.h 2003-04-01 14:32:40.000000000 +0000
@@ -505,6 +505,16 @@
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 char *get_EDID(struct pci_dev *pdev);
+extern void show_edid(unsigned char *edid);
+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);
+
+/* 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);
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH]: EDID parser
2003-04-01 15:32 Antonino Daplas
@ 2003-04-02 15:41 ` Antonino Daplas
0 siblings, 0 replies; 8+ messages in thread
From: Antonino Daplas @ 2003-04-02 15:41 UTC (permalink / raw)
To: Antonino Daplas; +Cc: James Simmons, Linux Fbdev development list
On Tue, 2003-04-01 at 23:32, Antonino Daplas wrote:
> Hi James,
>
> Attached is a diff against 2.5.66. It includes a reasonably complete
> EDID parser and also includes some new functions that can be used by
> fbdev drivers (for mode selection purposes)
>
> 1. fb_create_modedb()
>
> creates a mode database which can be fed to fb_find_mode(). This means
> that fb_find_mode() should not be __init anymore.
>
> 2. fb_destroy_modedb()
>
> destroy mode database created by fb_create_modedb()
>
> 3. fb_get_monitor_limits()
>
> gets monitor operating limits (max and min hscan, max and min refresh,
> max pixclock, DPMS and GTF capability)
>
> useful for validating video modes and calculating mode timings (if GTF
> capable)
>
> 4. show_edid()
>
> just prints EDID data into human-readable format.
>
> All of of the above depends on valid EDID data.
>
James,
Here's a revised patch. I was able to receive source code from SciTech
(c/o Kendall Bennett) which allowed me to fix bugs and complete the
parser. It's probably around 90-95% complete in terms of basic parsing.
It also fixes memory leaks which was present in the old patch.
Tony
diff -Naur linux-2.5.66-orig/drivers/video/edid.h linux-2.5.66-fbdev/drivers/video/edid.h
--- linux-2.5.66-orig/drivers/video/edid.h 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.5.66-fbdev/drivers/video/edid.h 2003-04-02 03:54:32.000000000 +0000
@@ -0,0 +1,138 @@
+/*
+ * 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__ */
diff -Naur linux-2.5.66-orig/drivers/video/fbmon.c linux-2.5.66-fbdev/drivers/video/fbmon.c
--- linux-2.5.66-orig/drivers/video/fbmon.c 2003-03-29 12:37:03.000000000 +0000
+++ linux-2.5.66-fbdev/drivers/video/fbmon.c 2003-04-02 03:54:27.000000000 +0000
@@ -1,7 +1,25 @@
/*
- * 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,30 @@
#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 <asm/prom.h>
#endif
+#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,122 +81,763 @@
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;
+ 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]);
+}
- 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;
+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)
+{
+ int tmp;
- return sign;
+ /* 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);
}
-static char *edid_get_monitor(unsigned char *block)
+static void parse_display_block(unsigned char *block)
{
- static char name[13];
- unsigned i;
- const unsigned char *ptr = block + DESCRIPTOR_DATA;
+ unsigned char c;
- for (i = 0; i < 13; i++, ptr++) {
- if (*ptr == 0xa) {
- name[i] = 0x00;
- return name;
+ 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");
}
- return name;
+ 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))
+ 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;
+}
+
+static int get_dst_timing(unsigned char *block,
+ struct fb_videomode *mode)
+{
+ int j, num = 0;
+
+ for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE)
+ num += get_std_timing(block, &mode[num]);
+
+ 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);
+}
+
+/**
+ * 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;
- vendor = edid_get_vendor(edid + ID_MANUFACTURER_NAME);
+ 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_monitor_block(block)) {
- monitor = edid_get_monitor(block);
+ 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;
}
}
+
+ /* 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;
+ }
- printk("EDID: detected %s %s\n", vendor, monitor);
+ 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;
+}
- block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+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_timing_block(block)) {
- parse_timing_block(block, var);
+ 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);
}
}
- return 1;
+ printk("========================================\n");
}
#ifdef CONFIG_PCI
char *get_EDID(struct pci_dev *pdev)
{
+ unsigned char *pedid = NULL;
#ifdef CONFIG_ALL_PPC
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) {
@@ -285,10 +850,9 @@
}
dp = dp->child;
}
- return pedid;
-#else
- return NULL;
#endif
+ show_edid(pedid);
+ return pedid;
}
#endif
@@ -679,8 +1243,12 @@
}
EXPORT_SYMBOL(parse_edid);
+EXPORT_SYMBOL(show_edid);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(get_EDID);
#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);
diff -Naur linux-2.5.66-orig/drivers/video/modedb.c linux-2.5.66-fbdev/drivers/video/modedb.c
--- linux-2.5.66-orig/drivers/video/modedb.c 2003-03-29 12:37:03.000000000 +0000
+++ linux-2.5.66-fbdev/drivers/video/modedb.c 2003-04-02 03:56:00.000000000 +0000
@@ -251,6 +251,110 @@
},
};
+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 @@
}
EXPORT_SYMBOL(__fb_try_mode);
+EXPORT_SYMBOL(vesa_modes);
diff -Naur linux-2.5.66-orig/include/linux/fb.h linux-2.5.66-fbdev/include/linux/fb.h
--- linux-2.5.66-orig/include/linux/fb.h 2003-03-29 21:09:54.000000000 +0000
+++ linux-2.5.66-fbdev/include/linux/fb.h 2003-04-02 14:36:16.000000000 +0000
@@ -492,6 +492,10 @@
extern int num_registered_fb;
/* drivers/video/fbmon.c */
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
#define FB_MAXTIMINGS 0
#define FB_VSYNCTIMINGS 1
#define FB_HSYNCTIMINGS 2
@@ -505,6 +509,16 @@
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 char *get_EDID(struct pci_dev *pdev);
+extern void show_edid(unsigned char *edid);
+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);
+
+/* 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);
-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb:
Dedicated Hosting for just $79/mo with 500 GB of bandwidth!
No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2003-04-03 17:18 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-04-03 16:38 [PATCH]: EDID parser Petr Vandrovec
2003-04-03 17:15 ` Sven Luther
-- strict thread matches above, loose matches on Subject: below --
2003-04-03 15:21 [Linux-fbdev-devel] " Alan Cox
2003-04-03 16:33 ` Geert Uytterhoeven
2003-04-03 17:10 ` [Linux-fbdev-devel] " Sven Luther
2003-04-03 16:15 ` Alan Cox
2003-04-03 17:18 ` Sven Luther
2003-04-02 21:55 [Linux-fbdev-devel] " James Simmons
2003-04-03 0:45 ` Antonino Daplas
2003-04-01 15:32 Antonino Daplas
2003-04-02 15:41 ` Antonino Daplas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).