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
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
2012-03-03 Matthew Garrett <mjg@redhat.com>
|
||||
2012-03-03 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
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.
|
||||
|
||||
2012-03-03 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* util/grub-install.in: Load efivars unconditionally.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
*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,
|
||||
|
|
54
include/grub/efi/edid.h
Normal file
54
include/grub/efi/edid.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_EFI_EDID_HEADER
|
||||
#define GRUB_EFI_EDID_HEADER 1
|
||||
|
||||
/* Based on UEFI specification. */
|
||||
|
||||
#define GRUB_EFI_EDID_ACTIVE_GUID \
|
||||
{ 0xbd8c1056, 0x9f36, 0x44ec, { 0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 }}
|
||||
|
||||
#define GRUB_EFI_EDID_DISCOVERED_GUID \
|
||||
{0x1c0c34f6,0xd380,0x41fa, {0xa0,0x49,0x8a,0xd0,0x6c,0x1a,0x66,0xaa}}
|
||||
|
||||
#define GRUB_EFI_EDID_OVERRIDE_GUID \
|
||||
{0x48ecb431,0xfb72,0x45c0, {0xa9,0x22,0xf4,0x58,0xfe,0x4,0xb,0xd5}}
|
||||
|
||||
struct grub_efi_edid_override;
|
||||
|
||||
typedef grub_efi_status_t
|
||||
(*grub_efi_edid_override_get_edid) (struct grub_efi_edid_override *this,
|
||||
grub_efi_handle_t *childhandle,
|
||||
grub_efi_uint32_t *attributes,
|
||||
grub_efi_uintn_t *edidsize,
|
||||
grub_efi_uint8_t *edid);
|
||||
struct grub_efi_edid_override {
|
||||
grub_efi_edid_override_get_edid get_edid;
|
||||
};
|
||||
|
||||
typedef struct grub_efi_edid_override grub_efi_edid_override_t;
|
||||
|
||||
|
||||
struct grub_efi_active_edid
|
||||
{
|
||||
grub_uint32_t size_of_edid;
|
||||
grub_uint8_t *edid;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -62,7 +62,8 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo
|
|||
grub_efi_uint32_t descriptor_version,
|
||||
grub_efi_memory_descriptor_t *virtual_map);
|
||||
void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
|
||||
const grub_efi_guid_t *guid);
|
||||
const grub_efi_guid_t *guid,
|
||||
grub_size_t *datasize_out);
|
||||
int
|
||||
EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
|
||||
const grub_efi_device_path_t *dp2);
|
||||
|
|
Loading…
Reference in a new issue