From 129185cfaae5969be4e49f5d898ed553b18d8502 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Tue, 14 Dec 2010 18:03:34 +0000 Subject: [PATCH] move more EDID-handling functions to generic code, and make videoinfo display EDID information --- ChangeLog.vbe-autodetect | 15 +++++++++--- grub-core/commands/videoinfo.c | 31 ++++++++++++++++++++++++ grub-core/video/i386/pc/vbe.c | 36 +++++++++++++--------------- grub-core/video/video.c | 43 ++++++++++++++++++++++++++++++++++ include/grub/video.h | 6 +++++ 5 files changed, 108 insertions(+), 23 deletions(-) diff --git a/ChangeLog.vbe-autodetect b/ChangeLog.vbe-autodetect index 0d96fc0a2..355ce00f6 100644 --- a/ChangeLog.vbe-autodetect +++ b/ChangeLog.vbe-autodetect @@ -3,24 +3,33 @@ Preferred resolution detection for VBE. * 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): - Likewise. + New function. (grub_vbe_bios_get_ddc_capabilities): Likewise. (grub_vbe_bios_read_edid): Likewise. - (grub_vbe_get_preferred_mode): Likewise. Try EDID followed by the - Flat Panel extension, in line with the X.org VESA driver. + (grub_vbe_get_preferred_mode): Likewise. (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 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 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. (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 structure. (grub_vbe_bios_get_flat_panel_info): Add prototype. (grub_vbe_bios_get_ddc_capabilities): 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 is more appropriate on a wider range of platforms than 640x480. diff --git a/grub-core/commands/videoinfo.c b/grub-core/commands/videoinfo.c index 10f77915b..56df943ec 100644 --- a/grub-core/commands/videoinfo.c +++ b/grub-core/commands/videoinfo.c @@ -77,6 +77,30 @@ hook (const struct grub_video_mode_info *info) 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 grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) @@ -120,6 +144,8 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), FOR_VIDEO_ADAPTERS (adapter) { + struct grub_video_edid_info edid_info; + grub_printf ("Adapter '%s':\n", adapter->name); if (!adapter->iterate) @@ -143,6 +169,11 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), 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->fini ()) diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index e2dcc151e..c6bb733a9 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -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_STATUS_OK) { - status = grub_vbe_bios_read_edid (&edid_info); - /* Bit 1 in the Feature Support field indicates that the first - Detailed Timing Description is the preferred timing mode. */ - if (status == GRUB_VBE_STATUS_OK - && grub_video_edid_checksum (&edid_info) == GRUB_ERR_NONE - && 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; - } + if (grub_video_get_edid (&edid_info) == GRUB_ERR_NONE + && grub_video_edid_preferred_mode (&edid_info, width, height) + == GRUB_ERR_NONE) + return GRUB_ERR_NONE; + + grub_errno = GRUB_ERR_NONE; } 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); } +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 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, .get_active_render_target = grub_video_fb_get_active_render_target, .iterate = grub_video_vbe_iterate, + .get_edid = grub_video_vbe_get_edid, .print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info, .next = 0 diff --git a/grub-core/video/video.c b/grub-core/video/video.c index f3ecab94d..84e98bb67 100644 --- a/grub-core/video/video.c +++ b/grub-core/video/video.c @@ -393,6 +393,49 @@ grub_video_edid_checksum (struct grub_video_edid_info *edid_info) 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 x[x]*/ static grub_err_t parse_modespec (const char *current_mode, int *width, int *height, int *depth) diff --git a/include/grub/video.h b/include/grub/video.h index 2cf1424c4..2251ed5f4 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -371,6 +371,8 @@ struct grub_video_adapter 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); }; 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_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, unsigned int modemask,