Use EDID on EFI.
* grub-core/kern/efi/efi.c (grub_efi_get_variable): New argument datasize_out. * grub-core/video/efi_gop.c (check_protocol): Check that GOP has usable modes. Set gop_handle. (grub_video_gop_get_edid): New function. (grub_gop_get_preferred_mode): Likewise. (grub_video_gop_setup): Use grub_gop_get_preferred_mode. (grub_video_efi_gop_adapter): Set .get_edid. * include/grub/efi/edid.h: New file. * include/grub/efi/efi.h (grub_efi_get_variable): Update proto. Also-By: Vladimir Serbinenko <phcoder@gmail.com>
This commit is contained in:
parent
32107ec02a
commit
3935dde2f2
5 changed files with 200 additions and 5 deletions
|
@ -183,7 +183,8 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
|
|||
}
|
||||
|
||||
void *
|
||||
grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid)
|
||||
grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
|
||||
grub_size_t *datasize_out)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
grub_efi_uintn_t datasize = 0;
|
||||
|
@ -192,6 +193,8 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid)
|
|||
void *data;
|
||||
grub_size_t len, len16;
|
||||
|
||||
*datasize_out = 0;
|
||||
|
||||
len = grub_strlen (var);
|
||||
len16 = len * GRUB_MAX_UTF16_PER_UTF8;
|
||||
var16 = grub_malloc ((len16 + 1) * sizeof (var16[0]));
|
||||
|
@ -204,6 +207,9 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid)
|
|||
|
||||
status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, NULL);
|
||||
|
||||
if (!datasize)
|
||||
return NULL;
|
||||
|
||||
data = grub_malloc (datasize);
|
||||
if (!data)
|
||||
{
|
||||
|
@ -215,7 +221,10 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid)
|
|||
grub_free (var16);
|
||||
|
||||
if (status == GRUB_EFI_SUCCESS)
|
||||
return data;
|
||||
{
|
||||
*datasize_out = datasize;
|
||||
return data;
|
||||
}
|
||||
|
||||
grub_free (data);
|
||||
return NULL;
|
||||
|
|
|
@ -27,14 +27,22 @@
|
|||
#include <grub/video_fb.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/edid.h>
|
||||
#include <grub/efi/graphics_output.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 efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
|
||||
static struct grub_efi_gop *gop;
|
||||
static unsigned old_mode;
|
||||
static int restore_needed;
|
||||
static grub_efi_handle_t gop_handle;
|
||||
|
||||
static int
|
||||
grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info));
|
||||
|
||||
static struct
|
||||
{
|
||||
|
@ -47,9 +55,37 @@ static struct
|
|||
static int
|
||||
check_protocol (void)
|
||||
{
|
||||
gop = grub_efi_locate_protocol (&graphics_output_guid, 0);
|
||||
if (gop)
|
||||
grub_efi_handle_t *handles;
|
||||
grub_efi_uintn_t num_handles, i;
|
||||
int have_usable_mode = 0;
|
||||
|
||||
auto int hook (const struct grub_video_mode_info *info);
|
||||
int hook (const struct grub_video_mode_info *info __attribute__ ((unused)))
|
||||
{
|
||||
have_usable_mode = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
|
||||
&graphics_output_guid, NULL, &num_handles);
|
||||
if (!handles || num_handles == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < num_handles; i++)
|
||||
{
|
||||
gop_handle = handles[i];
|
||||
gop = grub_efi_open_protocol (gop_handle, &graphics_output_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
grub_video_gop_iterate (hook);
|
||||
if (have_usable_mode)
|
||||
{
|
||||
grub_free (handles);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
gop = 0;
|
||||
gop_handle = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -220,6 +256,64 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info))
|
|||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_video_gop_get_edid (struct grub_video_edid_info *edid_info)
|
||||
{
|
||||
struct grub_efi_active_edid *edid;
|
||||
grub_size_t copy_size;
|
||||
|
||||
grub_memset (edid_info, 0, sizeof (*edid_info));
|
||||
|
||||
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)
|
||||
{
|
||||
char edidname[] = "agp-internal-edid";
|
||||
grub_size_t datasize;
|
||||
grub_uint8_t *data;
|
||||
data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize);
|
||||
if (data && datasize > 16)
|
||||
{
|
||||
copy_size = datasize - 16;
|
||||
if (copy_size > sizeof (*edid_info))
|
||||
copy_size = sizeof (*edid_info);
|
||||
grub_memcpy (edid_info, data + 16, copy_size);
|
||||
grub_free (data);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available");
|
||||
}
|
||||
|
||||
copy_size = edid->size_of_edid;
|
||||
if (copy_size > sizeof (*edid_info))
|
||||
copy_size = sizeof (*edid_info);
|
||||
grub_memcpy (edid_info, edid->edid, copy_size);
|
||||
|
||||
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;
|
||||
grub_err_t err;
|
||||
|
||||
err = grub_video_gop_get_edid (&edid_info);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_video_edid_checksum (&edid_info);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_video_edid_preferred_mode (&edid_info, width, height);
|
||||
if (err)
|
||||
return err;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_video_gop_setup (unsigned int width, unsigned int height,
|
||||
unsigned int mode_type,
|
||||
|
@ -232,10 +326,23 @@ grub_video_gop_setup (unsigned int width, unsigned int height,
|
|||
unsigned bpp;
|
||||
int found = 0;
|
||||
unsigned long long best_volume = 0;
|
||||
unsigned int preferred_width = 0, preferred_height = 0;
|
||||
|
||||
depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
|
||||
>> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
|
||||
|
||||
if (width == 0 && height == 0)
|
||||
{
|
||||
err = 1;
|
||||
grub_gop_get_preferred_mode (&preferred_width, &preferred_height);
|
||||
if (err)
|
||||
{
|
||||
preferred_width = 800;
|
||||
preferred_height = 600;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep current mode if possible. */
|
||||
if (gop->mode->info)
|
||||
{
|
||||
|
@ -270,6 +377,13 @@ 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_width && (info->width > preferred_width
|
||||
|| info->height > preferred_height))
|
||||
{
|
||||
grub_dprintf ("video", "GOP: mode %d: too large\n", mode);
|
||||
continue;
|
||||
}
|
||||
|
||||
bpp = grub_video_gop_get_bpp (info);
|
||||
if (!bpp)
|
||||
{
|
||||
|
@ -401,6 +515,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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue