move more EDID-handling functions to generic code, and make videoinfo display EDID information

This commit is contained in:
Colin Watson 2010-12-14 18:03:34 +00:00
parent 25d884a52a
commit 129185cfaa
5 changed files with 108 additions and 23 deletions

View file

@ -3,24 +3,33 @@
Preferred resolution detection for VBE. Preferred resolution detection for VBE.
* grub-core/video/video.c (grub_video_edid_checksum): New function. * grub-core/video/video.c (grub_video_edid_checksum): New function.
(grub_video_get_edid): Likewise.
(grub_video_edid_preferred_mode): Likewise. Try EDID followed by
the Flat Panel extension, in line with the X.org VESA driver.
* grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_flat_panel_info): * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_flat_panel_info):
Likewise. New function.
(grub_vbe_bios_get_ddc_capabilities): Likewise. (grub_vbe_bios_get_ddc_capabilities): Likewise.
(grub_vbe_bios_read_edid): Likewise. (grub_vbe_bios_read_edid): Likewise.
(grub_vbe_get_preferred_mode): Likewise. Try EDID followed by the (grub_vbe_get_preferred_mode): Likewise.
Flat Panel extension, in line with the X.org VESA driver.
(grub_video_vbe_setup): When the mode is "auto", try to get the (grub_video_vbe_setup): When the mode is "auto", try to get the
preferred mode from VBE, and use the largest mode that is no larger preferred mode from VBE, and use the largest mode that is no larger
than the preferred mode (some BIOSes expose a preferred mode that is than the preferred mode (some BIOSes expose a preferred mode that is
not in their mode list!). If this fails, fall back to 640x480 as a not in their mode list!). If this fails, fall back to 640x480 as a
safe conservative choice. safe conservative choice.
(grub_video_vbe_get_edid): New function.
(grub_video_vbe_adapter): Add get_edid.
* include/grub/video.h (struct grub_vbe_edid_info): New structure. * include/grub/video.h (struct grub_vbe_edid_info): New structure.
(grub_video_edid_checksum): Add prototype. (grub_video_edid_checksum): Add prototype.
(grub_video_get_edid): Likewise.
(grub_video_edid_preferred_mode): Likewise.
* include/grub/i386/pc/vbe.h (struct grub_vbe_flat_panel_info): New * include/grub/i386/pc/vbe.h (struct grub_vbe_flat_panel_info): New
structure. structure.
(grub_vbe_bios_get_flat_panel_info): Add prototype. (grub_vbe_bios_get_flat_panel_info): Add prototype.
(grub_vbe_bios_get_ddc_capabilities): Likewise. (grub_vbe_bios_get_ddc_capabilities): Likewise.
(grub_vbe_bios_read_edid): Likewise. (grub_vbe_bios_read_edid): Likewise.
* grub-core/commands/videoinfo.c (print_edid): New function.
(grub_cmd_videoinfo): Print EDID if available.
* util/grub.d/00_header.in (GRUB_GFXMODE): Default to "auto". This * util/grub.d/00_header.in (GRUB_GFXMODE): Default to "auto". This
is more appropriate on a wider range of platforms than 640x480. is more appropriate on a wider range of platforms than 640x480.

View file

@ -77,6 +77,30 @@ hook (const struct grub_video_mode_info *info)
return 0; return 0;
} }
static void
print_edid (struct grub_video_edid_info *edid_info)
{
unsigned int edid_width, edid_height;
if (grub_video_edid_checksum (edid_info))
{
grub_printf (" EDID checksum invalid\n");
grub_errno = GRUB_ERR_NONE;
return;
}
grub_printf (" EDID version: %u.%u\n",
edid_info->version, edid_info->revision);
if (grub_video_edid_preferred_mode (edid_info, &edid_width, &edid_height)
== GRUB_ERR_NONE)
grub_printf (" Preferred mode: %ux%u\n", edid_width, edid_height);
else
{
grub_printf (" No preferred mode available\n");
grub_errno = GRUB_ERR_NONE;
}
}
static grub_err_t static grub_err_t
grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args) int argc, char **args)
@ -120,6 +144,8 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
FOR_VIDEO_ADAPTERS (adapter) FOR_VIDEO_ADAPTERS (adapter)
{ {
struct grub_video_edid_info edid_info;
grub_printf ("Adapter '%s':\n", adapter->name); grub_printf ("Adapter '%s':\n", adapter->name);
if (!adapter->iterate) if (!adapter->iterate)
@ -143,6 +169,11 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
adapter->iterate (hook); adapter->iterate (hook);
if (adapter->get_edid (&edid_info) == GRUB_ERR_NONE)
print_edid (&edid_info);
else
grub_errno = GRUB_ERR_NONE;
if (adapter->id != id) if (adapter->id != id)
{ {
if (adapter->fini ()) if (adapter->fini ())

View file

@ -389,26 +389,12 @@ grub_vbe_get_preferred_mode (unsigned int *width, unsigned int *height)
&& (grub_vbe_bios_get_ddc_capabilities (&ddc_level) & 0xff) && (grub_vbe_bios_get_ddc_capabilities (&ddc_level) & 0xff)
== GRUB_VBE_STATUS_OK) == GRUB_VBE_STATUS_OK)
{ {
status = grub_vbe_bios_read_edid (&edid_info); if (grub_video_get_edid (&edid_info) == GRUB_ERR_NONE
/* Bit 1 in the Feature Support field indicates that the first && grub_video_edid_preferred_mode (&edid_info, width, height)
Detailed Timing Description is the preferred timing mode. */ == GRUB_ERR_NONE)
if (status == GRUB_VBE_STATUS_OK return GRUB_ERR_NONE;
&& grub_video_edid_checksum (&edid_info) == GRUB_ERR_NONE
&& edid_info.version == 1 /* we don't understand later versions */ grub_errno = GRUB_ERR_NONE;
&& (edid_info.feature_support
& GRUB_VIDEO_EDID_FEATURE_PREFERRED_TIMING_MODE)
&& edid_info.detailed_timings[0].pixel_clock)
{
*width = edid_info.detailed_timings[0].horizontal_active_lo
| (((unsigned int)
(edid_info.detailed_timings[0].horizontal_hi & 0xf0))
<< 4);
*height = edid_info.detailed_timings[0].vertical_active_lo
| (((unsigned int)
(edid_info.detailed_timings[0].vertical_hi & 0xf0))
<< 4);
return GRUB_ERR_NONE;
}
} }
status = grub_vbe_bios_get_flat_panel_info (&flat_panel_info); status = grub_vbe_bios_get_flat_panel_info (&flat_panel_info);
@ -978,6 +964,15 @@ grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info,
return grub_video_fb_get_info_and_fini (mode_info, framebuf); return grub_video_fb_get_info_and_fini (mode_info, framebuf);
} }
static grub_err_t
grub_video_vbe_get_edid (struct grub_video_edid_info *edid_info)
{
if (grub_vbe_bios_read_edid (edid_info) != GRUB_VBE_STATUS_OK)
return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available");
return GRUB_ERR_NONE;
}
static void static void
grub_video_vbe_print_adapter_specific_info (void) grub_video_vbe_print_adapter_specific_info (void)
{ {
@ -1022,6 +1017,7 @@ static struct grub_video_adapter grub_video_vbe_adapter =
.set_active_render_target = grub_video_fb_set_active_render_target, .set_active_render_target = grub_video_fb_set_active_render_target,
.get_active_render_target = grub_video_fb_get_active_render_target, .get_active_render_target = grub_video_fb_get_active_render_target,
.iterate = grub_video_vbe_iterate, .iterate = grub_video_vbe_iterate,
.get_edid = grub_video_vbe_get_edid,
.print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info, .print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info,
.next = 0 .next = 0

View file

@ -393,6 +393,49 @@ grub_video_edid_checksum (struct grub_video_edid_info *edid_info)
return grub_errno; return grub_errno;
} }
grub_err_t
grub_video_get_edid (struct grub_video_edid_info *edid_info)
{
if (! grub_video_adapter_active)
return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
if (! grub_video_adapter_active->get_edid)
return grub_error (GRUB_ERR_BAD_DEVICE,
"EDID information unavailable for this video mode");
if (grub_video_adapter_active->get_edid (edid_info) != GRUB_ERR_NONE)
return grub_errno;
if (grub_video_edid_checksum (edid_info) != GRUB_ERR_NONE)
return grub_errno;
return GRUB_ERR_NONE;
}
grub_err_t
grub_video_edid_preferred_mode (struct grub_video_edid_info *edid_info,
unsigned int *width, unsigned int *height)
{
/* Bit 1 in the Feature Support field indicates that the first
Detailed Timing Description is the preferred timing mode. */
if (edid_info->version == 1 /* we don't understand later versions */
&& (edid_info->feature_support
& GRUB_VIDEO_EDID_FEATURE_PREFERRED_TIMING_MODE)
&& edid_info->detailed_timings[0].pixel_clock)
{
*width = edid_info->detailed_timings[0].horizontal_active_lo
| (((unsigned int)
(edid_info->detailed_timings[0].horizontal_hi & 0xf0))
<< 4);
*height = edid_info->detailed_timings[0].vertical_active_lo
| (((unsigned int)
(edid_info->detailed_timings[0].vertical_hi & 0xf0))
<< 4);
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_BAD_DEVICE, "no preferred mode available");
}
/* Parse <width>x<height>[x<depth>]*/ /* Parse <width>x<height>[x<depth>]*/
static grub_err_t static grub_err_t
parse_modespec (const char *current_mode, int *width, int *height, int *depth) parse_modespec (const char *current_mode, int *width, int *height, int *depth)

View file

@ -371,6 +371,8 @@ struct grub_video_adapter
int (*iterate) (int (*hook) (const struct grub_video_mode_info *info)); int (*iterate) (int (*hook) (const struct grub_video_mode_info *info));
grub_err_t (*get_edid) (struct grub_video_edid_info *edid_info);
void (*print_adapter_specific_info) (void); void (*print_adapter_specific_info) (void);
}; };
typedef struct grub_video_adapter *grub_video_adapter_t; typedef struct grub_video_adapter *grub_video_adapter_t;
@ -484,6 +486,10 @@ grub_err_t EXPORT_FUNC (grub_video_set_active_render_target) (struct grub_video_
grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target); grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target);
grub_err_t grub_video_edid_checksum (struct grub_video_edid_info *edid_info); grub_err_t grub_video_edid_checksum (struct grub_video_edid_info *edid_info);
grub_err_t grub_video_get_edid (struct grub_video_edid_info *edid_info);
grub_err_t grub_video_edid_preferred_mode (struct grub_video_edid_info *edid_info,
unsigned int *width,
unsigned int *height);
grub_err_t EXPORT_FUNC (grub_video_set_mode) (const char *modestring, grub_err_t EXPORT_FUNC (grub_video_set_mode) (const char *modestring,
unsigned int modemask, unsigned int modemask,