grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 4/4] Add support for getting EDID via EFI


From: Matthew Garrett
Subject: [PATCH 4/4] Add support for getting EDID via EFI
Date: Wed, 8 Feb 2012 11:51:58 -0500

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  <address@hidden>
 
+       * 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  <address@hidden>
+
        * 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]