public inbox for linux-fbdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: gregkh@linuxfoundation.org, deller@gmx.de, sam@ravnborg.org
Cc: linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org,
	Thomas Zimmermann <tzimmermann@suse.de>
Subject: [PATCH v2 12/13] lib/fonts: Store font data for user space with font_data_export()
Date: Mon,  2 Mar 2026 15:08:46 +0100	[thread overview]
Message-ID: <20260302141255.518657-13-tzimmermann@suse.de> (raw)
In-Reply-To: <20260302141255.518657-1-tzimmermann@suse.de>

Add font_data_export() and update consoles to use it.

The helper font_data_export() is based on code in fbcon_get_font().
It extends the size of a single glyph to match the requested vpitch,
which us usually 32 bytes for fonts from user space. Internal fonts
have a pitch according to the glyph's height.

The implementation of font_data_export() differs in several ways from
the original code. The original implementation distinguished between
different pitches of the font data. This is not necessary as the pitch
is a parameter in the copying.

There was also special handling for a font pitch of 3 bytes, which got
expanded to 4 bytes (with trailing bits on each scanline). The logic
originated from long before git history exists even in the historical
tree. So it is not clear why this was implemented. It is not what user
space expects. The setfont utitlity loads font with 3-bytes pitches and
expects to read such fonts with a 3-byte pitch. For any font width, the
font pitch is always the width extended to the next multiple of 8. See
[1] for the user-space font-reading code.

With the changes ot handling the font pitches, font_data_export() replaces
the original code's various special cases with a single copying logic.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://github.com/legionus/kbd/blob/v2.9.0/src/libkfont/kdfontop.c#L73 # [1]
---
 drivers/video/fbdev/core/fbcon.c | 57 ++------------------------------
 include/linux/font.h             |  1 +
 lib/fonts/fonts.c                | 40 ++++++++++++++++++++++
 3 files changed, 43 insertions(+), 55 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 53677c09a0ec..8641b0b3edc4 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2282,68 +2282,15 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
 
 static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
 {
-	struct fbcon_display *p = &fb_display[vc->vc_num];
-	font_data_t *fontdata = p->fontdata;
-	u8 *data = font->data;
-	int i, j;
+	const struct fbcon_display *p = &fb_display[vc->vc_num];
 
 	font->width = vc->vc_font.width;
 	font->height = vc->vc_font.height;
 	if (font->height > vpitch)
 		return -ENOSPC;
 	font->charcount = vc->vc_hi_font_mask ? 512 : 256;
-	if (!font->data)
-		return 0;
-
-	if (font->width <= 8) {
-		j = vc->vc_font.height;
-		if (font->charcount * j > font_data_size(fontdata))
-			return -EINVAL;
 
-		for (i = 0; i < font->charcount; i++) {
-			memcpy(data, fontdata, j);
-			memset(data + j, 0, vpitch - j);
-			data += vpitch;
-			fontdata += j;
-		}
-	} else if (font->width <= 16) {
-		j = vc->vc_font.height * 2;
-		if (font->charcount * j > font_data_size(fontdata))
-			return -EINVAL;
-
-		for (i = 0; i < font->charcount; i++) {
-			memcpy(data, fontdata, j);
-			memset(data + j, 0, 2*vpitch - j);
-			data += 2*vpitch;
-			fontdata += j;
-		}
-	} else if (font->width <= 24) {
-		if (font->charcount * (vc->vc_font.height * sizeof(u32)) > font_data_size(fontdata))
-			return -EINVAL;
-
-		for (i = 0; i < font->charcount; i++) {
-			for (j = 0; j < vc->vc_font.height; j++) {
-				*data++ = fontdata[0];
-				*data++ = fontdata[1];
-				*data++ = fontdata[2];
-				fontdata += sizeof(u32);
-			}
-			memset(data, 0, 3 * (vpitch - j));
-			data += 3 * (vpitch - j);
-		}
-	} else {
-		j = vc->vc_font.height * 4;
-		if (font->charcount * j > font_data_size(fontdata))
-			return -EINVAL;
-
-		for (i = 0; i < font->charcount; i++) {
-			memcpy(data, fontdata, j);
-			memset(data + j, 0, 4 * vpitch - j);
-			data += 4 * vpitch;
-			fontdata += j;
-		}
-	}
-	return 0;
+	return font_data_export(p->fontdata, font, vpitch);
 }
 
 /* set/clear vc_hi_font_mask and update vc attrs accordingly */
diff --git a/include/linux/font.h b/include/linux/font.h
index d3b8ca240152..e2e02e40c365 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -62,6 +62,7 @@ void font_data_get(font_data_t *fd);
 bool font_data_put(font_data_t *fd);
 unsigned int font_data_size(font_data_t *fd);
 bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
+int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch);
 
 /*
  * Font description
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 9b5355f6d2dc..1830e6ae9c87 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -202,6 +202,46 @@ bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
 }
 EXPORT_SYMBOL_GPL(font_data_is_equal);
 
+/**
+ * font_data_export - Stores font data for user space
+ * @fd: Font data
+ * @font: A font for user space
+ * @vpitch: The size of a single glyph in @font in bytes
+ *
+ * Store the font data given in @fd to the font in @font. Values and
+ * pointers in @font are pre-initialized. This helper mostly checks some
+ * corner cases and translates glyph sizes according to the value given
+ * @vpitch.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch)
+{
+	const unsigned char *font_data = font_data_buf(fd);
+	unsigned char *data = font->data;
+	unsigned int pitch = console_font_pitch(font);
+	unsigned int glyphsize, i;
+
+	if (!font->width || !font->height || !font->charcount || !font->data)
+		return 0;
+
+	glyphsize = font->height * pitch;
+
+	if (font->charcount * glyphsize > font_data_size(fd))
+		return -EINVAL;
+
+	for (i = 0; i < font->charcount; i++) {
+		memcpy(data, font_data, glyphsize);
+		memset(data + glyphsize, 0, pitch * vpitch - glyphsize);
+		data += pitch * vpitch;
+		font_data += glyphsize;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(font_data_export);
+
 /*
  * Font lookup
  */
-- 
2.53.0


  parent reply	other threads:[~2026-03-02 14:13 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-02 14:08 [PATCH v2 00/13] vc,fbcon,fonts: Proper handling of font data Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 01/13] fbdev: Declare src parameter of fb_pad_ helpers as constant Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 02/13] vt: Remove trailing whitespaces Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 03/13] vt: Store font in struct vc_font Thomas Zimmermann
2026-03-03 14:31   ` Helge Deller
2026-03-04  7:49     ` Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 04/13] vt: Calculate font-buffer size with vc_font_size() Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 05/13] lib/fonts: Remove trailing whitespaces Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 06/13] lib/fonts: Remove FNTCHARCNT() Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 07/13] lib/fonts: Store font data as font_data_t; update consoles Thomas Zimmermann
2026-03-03 14:57   ` Helge Deller
2026-03-04  7:51     ` Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 08/13] lib/fonts: Read font size with font_data_size() Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 09/13] lib/fonts: Compare font data for equality with font_data_is_equal() Thomas Zimmermann
2026-03-05  0:23   ` Nathan Chancellor
2026-03-05  9:31     ` Thomas Zimmermann
2026-03-05 20:12       ` Nathan Chancellor
2026-03-02 14:08 ` [PATCH v2 10/13] lib/fonts: Manage font-data lifetime with font_data_get/_put() Thomas Zimmermann
2026-03-02 14:08 ` [PATCH v2 11/13] lib/fonts: Create font_data_t from struct console_font with font_data_import() Thomas Zimmermann
2026-03-02 14:08 ` Thomas Zimmermann [this message]
2026-03-02 14:08 ` [PATCH v2 13/13] lib/fonts: Remove internal symbols and macros from public header file Thomas Zimmermann
2026-03-03 15:29 ` [PATCH v2 00/13] vc,fbcon,fonts: Proper handling of font data Helge Deller
2026-03-04  9:11   ` Thomas Zimmermann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260302141255.518657-13-tzimmermann@suse.de \
    --to=tzimmermann@suse.de \
    --cc=deller@gmx.de \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sam@ravnborg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox