EFI gives a couple of defined methods for retrieving the EDID, so make use of them. Some Apple devices don't provide these but do stash the EDID in an nvram variable - grab it from there if it exists. --- ChangeLog | 8 +++++ grub-core/video/efi_gop.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 26d779b..d46b3d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2012-02-08 Matthew Garrett <m...@redhat.com> + * grub-core/video/efi_gop.c (grub_video_gop_get_edid): Add support for + retrieving the EDID via EFI. Implements the active and discovered + protocols, falling back to a variable for Apple devices. + (grub_video_gop_get_preferred_mode): Retrieve the EDID preferred mode + when possible. + +2012-02-08 Matthew Garrett <m...@redhat.com> + * grub-core/video/efi_gop.c (check_protocol): Prefer GOP devices which implement the pci_io protocol. diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c index 47e3ee9..f4c563d 100644 --- a/grub-core/video/efi_gop.c +++ b/grub-core/video/efi_gop.c @@ -28,12 +28,16 @@ #include <grub/efi/api.h> #include <grub/efi/efi.h> #include <grub/efi/graphics_output.h> +#include <grub/efi/edid.h> #include <grub/efi/pci.h> GRUB_MOD_LICENSE ("GPLv3+"); static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GOP_GUID; +static grub_efi_guid_t active_edid_guid = GRUB_EFI_EDID_ACTIVE_GUID; +static grub_efi_guid_t discovered_edid_guid = GRUB_EFI_EDID_DISCOVERED_GUID; static grub_efi_guid_t pci_io_guid = GRUB_EFI_PCI_IO_GUID; +static grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; static struct grub_efi_gop *gop; static grub_efi_handle_t gop_handle; static unsigned old_mode; @@ -257,6 +261,53 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info)) } static grub_err_t +grub_video_gop_get_edid (struct grub_video_edid_info *edid_info) +{ + struct grub_efi_active_edid *edid; + grub_uint8_t edidname[] = "agp-internal-edid"; + grub_uint8_t *data; + + edid = grub_efi_open_protocol(gop_handle, &active_edid_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!edid || edid->size_of_edid == 0) { + edid = grub_efi_open_protocol(gop_handle, &discovered_edid_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + + if (!edid || edid->size_of_edid == 0) { + data = grub_efi_get_variable(edidname, &efi_var_guid); + if (data) + { + grub_memcpy(edid_info, data + 16, sizeof(*edid_info)); + grub_free(data); + return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available"); + } + + grub_memcpy (&edid_info, edid->edid, sizeof(edid_info)); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_gop_get_preferred_mode (unsigned int *width, unsigned int *height) +{ + struct grub_video_edid_info edid_info; + + if (grub_video_gop_get_edid(&edid_info) == GRUB_ERR_NONE) + { + if (grub_video_edid_checksum (&edid_info) == GRUB_ERR_NONE + && grub_video_edid_preferred_mode (&edid_info, width, height) + == GRUB_ERR_NONE) + return GRUB_ERR_NONE; + else + grub_dprintf("video", "invalid edid"); + } + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot get preferred mode"); +} + +static grub_err_t grub_video_gop_setup (unsigned int width, unsigned int height, unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) @@ -268,10 +319,18 @@ grub_video_gop_setup (unsigned int width, unsigned int height, unsigned bpp; int found = 0; unsigned long long best_volume = 0; + int preferred_mode = 0; depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + if (width == 0 && height == 0) + { + grub_gop_get_preferred_mode (&width, &height); + if (grub_errno == GRUB_ERR_NONE) + preferred_mode = 1; + } + /* Keep current mode if possible. */ if (gop->mode->info) { @@ -306,6 +365,15 @@ grub_video_gop_setup (unsigned int width, unsigned int height, grub_dprintf ("video", "GOP: mode %d: %dx%d\n", mode, info->width, info->height); + if (preferred_mode) + { + if (info->width > width || info->height > height) + { + grub_dprintf ("video", "GOP: mode %d: too large\n", mode); + continue; + } + } + bpp = grub_video_gop_get_bpp (info); if (!bpp) { @@ -437,6 +505,7 @@ static struct grub_video_adapter grub_video_gop_adapter = .setup = grub_video_gop_setup, .get_info = grub_video_fb_get_info, .get_info_and_fini = grub_video_gop_get_info_and_fini, + .get_edid = grub_video_gop_get_edid, .set_palette = grub_video_fb_set_palette, .get_palette = grub_video_fb_get_palette, .set_viewport = grub_video_fb_set_viewport, -- 1.7.7.6 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel