Page MenuHomeFreeBSD

D28849.diff
No OneTemporary

D28849.diff

diff --git a/stand/common/gfx_fb.h b/stand/common/gfx_fb.h
--- a/stand/common/gfx_fb.h
+++ b/stand/common/gfx_fb.h
@@ -109,6 +109,8 @@
uint8_t checksum;
} __packed;
+extern struct vesa_edid_info *edid_info;
+
#define STD_TIMINGS 8
#define DET_TIMINGS 4
diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c
--- a/stand/common/gfx_fb.c
+++ b/stand/common/gfx_fb.c
@@ -1863,6 +1863,113 @@
}
}
+/* Return w^2 + h^2 or 0, if the dimensions are unknown */
+static unsigned
+edid_diagonal_squared(void)
+{
+ unsigned w, h;
+
+ if (edid_info == NULL)
+ return (0);
+
+ w = edid_info->display.max_horizontal_image_size;
+ h = edid_info->display.max_vertical_image_size;
+
+ /* If either one is 0, we have aspect ratio, not size */
+ if (w == 0 || h == 0)
+ return (0);
+
+ /*
+ * some monitors encode the aspect ratio instead of the physical size.
+ */
+ if ((w == 16 && h == 9) || (w == 16 && h == 10) ||
+ (w == 4 && h == 3) || (w == 5 && h == 4))
+ return (0);
+
+ /*
+ * translate cm to inch, note we scale by 100 here.
+ */
+ w = w * 100 / 254;
+ h = h * 100 / 254;
+
+ /* Return w^2 + h^2 */
+ return (w * w + h * h);
+}
+
+/*
+ * calculate pixels per inch.
+ */
+static unsigned
+gfx_get_ppi(void)
+{
+ unsigned dp, di;
+
+ di = edid_diagonal_squared();
+ if (di == 0)
+ return (0);
+
+ dp = gfx_state.tg_fb.fb_width *
+ gfx_state.tg_fb.fb_width +
+ gfx_state.tg_fb.fb_height *
+ gfx_state.tg_fb.fb_height;
+
+ return (isqrt(dp / di));
+}
+
+/*
+ * Calculate font size from density independent pixels (dp):
+ * ((16dp * ppi) / 160) * display_factor.
+ * Here we are using fixed constants: 1dp == 160 ppi and
+ * display_factor 2.
+ *
+ * We are rounding font size up and are searching for font which is
+ * not smaller than calculated size value.
+ */
+static vt_font_bitmap_data_t *
+gfx_get_font(void)
+{
+ unsigned ppi, size;
+ vt_font_bitmap_data_t *font = NULL;
+ struct fontlist *fl, *next;
+
+ /* Text mode is not supported here. */
+ if (gfx_state.tg_fb_type == FB_TEXT)
+ return (NULL);
+
+ ppi = gfx_get_ppi();
+ if (ppi == 0)
+ return (NULL);
+
+ /*
+ * We will search for 16dp font.
+ * We are using scale up by 10 for roundup.
+ */
+ size = (16 * ppi * 10) / 160;
+ /* Apply display factor 2. */
+ size = roundup(size * 2, 10) / 10;
+
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ next = STAILQ_NEXT(fl, font_next);
+
+ /*
+ * If this is last font or, if next font is smaller,
+ * we have our font. Make sure, it actually is loaded.
+ */
+ if (next == NULL || next->font_data->vfbd_height < size) {
+ font = fl->font_data;
+ if (font->vfbd_font == NULL ||
+ fl->font_flags == FONT_RELOAD) {
+ if (fl->font_load != NULL &&
+ fl->font_name != NULL)
+ font = fl->font_load(fl->font_name);
+ }
+ break;
+ }
+ }
+
+ return (font);
+}
+
static vt_font_bitmap_data_t *
set_font(teken_unit_t *rows, teken_unit_t *cols, teken_unit_t h, teken_unit_t w)
{
@@ -1887,6 +1994,9 @@
}
}
+ if (font == NULL)
+ font = gfx_get_font();
+
if (font != NULL) {
*rows = height / font->vfbd_height;
*cols = width / font->vfbd_width;
diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c
--- a/stand/efi/libefi/efi_console.c
+++ b/stand/efi/libefi/efi_console.c
@@ -952,13 +952,24 @@
/*
* setup_font() can adjust terminal size.
- * Note, we do use UEFI terminal dimensions first,
- * this is because the font selection will attempt
- * to achieve at least this terminal dimension and
- * we do not end up with too small font.
+ * We can see two kind of bad happening.
+ * We either can get too small console font - requested
+ * terminal size is large, display resolution is
+ * large, and we get very small font.
+ * Or, we can get too large font - requested
+ * terminal size is small and this will cause large
+ * font to be selected.
+ * Now, the setup_font() is updated to consider
+ * display density and this should give us mostly
+ * acceptable font. However, the catch is, not all
+ * display devices will give us display density.
+ * Still, we do hope, external monitors do - this is
+ * where the display size will matter the most.
+ * And for laptop screens, we should still get good
+ * results by requesting 80x25 terminal.
*/
- gfx_state.tg_tp.tp_row = rows;
- gfx_state.tg_tp.tp_col = cols;
+ gfx_state.tg_tp.tp_row = 25;
+ gfx_state.tg_tp.tp_col = 80;
setup_font(&gfx_state, fb_height, fb_width);
rows = gfx_state.tg_tp.tp_row;
cols = gfx_state.tg_tp.tp_col;
diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c
--- a/stand/efi/loader/framebuffer.c
+++ b/stand/efi/loader/framebuffer.c
@@ -38,6 +38,8 @@
#include <efilib.h>
#include <efiuga.h>
#include <efipciio.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/EdidDiscovered.h>
#include <machine/metadata.h>
#include "bootstrap.h"
@@ -47,6 +49,12 @@
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
+static EFI_GUID active_edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
+static EFI_GUID discovered_edid_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID;
+static EFI_HANDLE gop_handle;
+
+/* Cached EDID. */
+struct vesa_edid_info *edid_info = NULL;
static EFI_GRAPHICS_OUTPUT *gop;
static EFI_UGA_DRAW_PROTOCOL *uga;
@@ -467,10 +475,71 @@
return (0);
}
+/*
+ * Fetch EDID info. Caller must free the buffer.
+ */
+static struct vesa_edid_info *
+efifb_gop_get_edid(EFI_HANDLE h)
+{
+ const uint8_t magic[] = EDID_MAGIC;
+ EFI_EDID_ACTIVE_PROTOCOL *edid;
+ struct vesa_edid_info *edid_infop;
+ EFI_GUID *guid;
+ EFI_STATUS status;
+ size_t size;
+
+ guid = &active_edid_guid;
+ status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (status != EFI_SUCCESS ||
+ edid->SizeOfEdid == 0) {
+ guid = &discovered_edid_guid;
+ status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (status != EFI_SUCCESS ||
+ edid->SizeOfEdid == 0)
+ return (NULL);
+ }
+
+ size = MAX(sizeof(*edid_infop), edid->SizeOfEdid);
+
+ edid_infop = calloc(1, size);
+ if (edid_infop == NULL)
+ return (NULL);
+
+ memcpy(edid_infop, edid->Edid, edid->SizeOfEdid);
+
+ /* Validate EDID */
+ if (memcmp(edid_infop, magic, sizeof (magic)) != 0)
+ goto error;
+
+ if (edid_infop->header.version != 1)
+ goto error;
+
+ return (edid_infop);
+error:
+ free(edid_infop);
+ return (NULL);
+}
+
+static bool
+efifb_get_edid(edid_res_list_t *res)
+{
+ bool rv = false;
+
+ if (edid_info == NULL)
+ edid_info = efifb_gop_get_edid(gop_handle);
+
+ if (edid_info != NULL)
+ rv = gfx_get_edid_resolution(edid_info, res);
+
+ return (rv);
+}
+
int
efi_find_framebuffer(teken_gfx_t *gfx_state)
{
- EFI_HANDLE h, *hlist;
+ EFI_HANDLE *hlist;
UINTN nhandles, i, hsize;
struct efi_fb efifb;
EFI_STATUS status;
@@ -498,23 +567,25 @@
/*
* Search for ConOut protocol, if not found, use first handle.
*/
- h = *hlist;
+ gop_handle = *hlist;
for (i = 0; i < nhandles; i++) {
void *dummy = NULL;
status = OpenProtocolByHandle(hlist[i], &conout_guid, &dummy);
if (status == EFI_SUCCESS) {
- h = hlist[i];
+ gop_handle = hlist[i];
break;
}
}
- status = OpenProtocolByHandle(h, &gop_guid, (void **)&gop);
+ status = OpenProtocolByHandle(gop_handle, &gop_guid, (void **)&gop);
free(hlist);
if (status == EFI_SUCCESS) {
gfx_state->tg_fb_type = FB_GOP;
gfx_state->tg_private = gop;
+ if (edid_info == NULL)
+ edid_info = efifb_gop_get_edid(gop_handle);
} else {
status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga);
if (status == EFI_SUCCESS) {
@@ -767,9 +838,25 @@
} else if (strcmp(argv[1], "off") == 0) {
(void) cons_update_mode(false);
} else if (strcmp(argv[1], "get") == 0) {
+ edid_res_list_t res;
+
if (argc != 2)
goto usage;
+ TAILQ_INIT(&res);
efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info);
+ if (efifb_get_edid(&res)) {
+ struct resolution *rp;
+
+ printf("EDID");
+ while ((rp = TAILQ_FIRST(&res)) != NULL) {
+ printf(" %dx%d", rp->width, rp->height);
+ TAILQ_REMOVE(&res, rp, next);
+ free(rp);
+ }
+ printf("\n");
+ } else {
+ printf("no EDID information\n");
+ }
print_efifb(gop->Mode->Mode, &efifb, 1);
printf("\n");
} else if (!strcmp(argv[1], "list")) {
@@ -778,6 +865,7 @@
if (argc != 2)
goto usage;
+
pager_open();
for (mode = 0; mode < gop->Mode->MaxMode; mode++) {
status = gop->QueryMode(gop, mode, &infosz, &info);
diff --git a/stand/i386/libi386/vbe.c b/stand/i386/libi386/vbe.c
--- a/stand/i386/libi386/vbe.c
+++ b/stand/i386/libi386/vbe.c
@@ -51,6 +51,7 @@
static uint16_t *vbe_mode_list;
static size_t vbe_mode_list_size;
+struct vesa_edid_info *edid_info = NULL;
/* The default VGA color palette format is 6 bits per primary color. */
int palette_format = 6;
@@ -836,34 +837,40 @@
static bool
vbe_get_edid(edid_res_list_t *res)
{
- struct vesa_edid_info *edid_info;
+ struct vesa_edid_info *edidp;
const uint8_t magic[] = EDID_MAGIC;
int ddc_caps;
bool ret = false;
+ if (edid_info != NULL)
+ return (gfx_get_edid_resolution(edid_info, res));
+
ddc_caps = biosvbe_ddc_caps();
if (ddc_caps == 0) {
return (ret);
}
- edid_info = bio_alloc(sizeof (*edid_info));
- if (edid_info == NULL)
+ edidp = bio_alloc(sizeof(*edidp));
+ if (edidp == NULL)
return (ret);
- memset(edid_info, 0, sizeof (*edid_info));
+ memset(edidp, 0, sizeof(*edidp));
- if (VBE_ERROR(biosvbe_ddc_read_edid(0, edid_info)))
+ if (VBE_ERROR(biosvbe_ddc_read_edid(0, edidp)))
goto done;
- if (memcmp(edid_info, magic, sizeof (magic)) != 0)
+ if (memcmp(edidp, magic, sizeof(magic)) != 0)
goto done;
/* Unknown EDID version. */
- if (edid_info->header.version != 1)
+ if (edidp->header.version != 1)
goto done;
- ret = gfx_get_edid_resolution(edid_info, res);
+ ret = gfx_get_edid_resolution(edidp, res);
+ edid_info = malloc(sizeof(*edid_info));
+ if (edid_info != NULL)
+ memcpy(edid_info, edidp, sizeof (*edid_info));
done:
- bio_free(edid_info, sizeof (*edid_info));
+ bio_free(edidp, sizeof(*edidp));
return (ret);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 22, 3:56 PM (4 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15556252
Default Alt Text
D28849.diff (10 KB)

Event Timeline