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.
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)
FOR_VIDEO_ADAPTERS (adapter)
{
+ struct grub_video_edid_info edid_info;
+
grub_printf ("Adapter '%s':\n", adapter->name);
if (!adapter->iterate)
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 ())
&& (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);
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)
{
.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
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 <width>x<height>[x<depth>]*/
static grub_err_t
parse_modespec (const char *current_mode, int *width, int *height, int *depth)
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;
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,