* [PATCH 0/6] fbcon: Clean up glyph handling on redraws
@ 2026-10-27 13:27 Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 1/6] fbcon: Use unsigned char for glyph data Thomas Zimmermann
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Fbcon's drawing functions open-code much of the glyph handling. Use
font helpers instead. Makes fbcon more consistent and easier to
understand.
Patch 1 updates fbcon to use unsigned char for glyph buffers. This
is consistent with the font code and font_data_t.
Patches 2 and 3 update font rotation to return rotated glyphs as
font_data_t. A rotated font can now use the same interfaces as the
unrotated source font. Fbcon uses this to ref count the font buffer.
Patches 4 to 6 update various parts of fbcon to use font helpers
instead of open-coding access to font_data_t. Having the rotated
font as font_data_t makes this convenient.
Tested with fbcon on DRM's bochs driver (qemu).
Thomas Zimmermann (6):
fbcon: Use unsigned char for glyph data
lib/fonts: Provide internal helpers for allocating font_data_t
lib/fonts, fbcon: Use font_data_t for rotated fonts
fbcon: Refactor size calculation for cursor buffers
fbcon: Look up glyphs using the font interface
fbcon: Handle characters with no glyph defined in a consistent way
drivers/video/fbdev/core/bitblit.c | 82 +++++++++++++++----------
drivers/video/fbdev/core/fbcon.c | 3 +-
drivers/video/fbdev/core/fbcon.h | 5 +-
drivers/video/fbdev/core/fbcon_ccw.c | 56 +++++++++++------
drivers/video/fbdev/core/fbcon_cw.c | 57 ++++++++++-------
drivers/video/fbdev/core/fbcon_rotate.c | 19 +++---
drivers/video/fbdev/core/fbcon_ud.c | 77 +++++++++++++++--------
include/linux/font.h | 5 +-
lib/fonts/font.h | 12 ++++
lib/fonts/font_rotate.c | 32 ++++------
lib/fonts/fonts.c | 63 ++++++++++++-------
11 files changed, 254 insertions(+), 157 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/6] fbcon: Use unsigned char for glyph data
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
@ 2026-10-27 13:27 ` Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 2/6] lib/fonts: Provide internal helpers for allocating font_data_t Thomas Zimmermann
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Represent glyph data as unsigned char, as done by font_data_t. Convert
all related code. Also declare source buffers with glyph data as const
because internal fonts reside in read-only memory. Avoid writing them.
We still use char for glyph data in struct fb_image. The type is part
of the kernel uAPI and therefore cannot be changed. Fall back to type
casting in this case.
Destination buffers for font drawing are still u8. This is framebuffer
memory provided by graphics hardware.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/bitblit.c | 25 ++++++++++++++-----------
drivers/video/fbdev/core/fbcon.h | 4 ++--
drivers/video/fbdev/core/fbcon_ccw.c | 22 ++++++++++++----------
drivers/video/fbdev/core/fbcon_cw.c | 22 ++++++++++++----------
drivers/video/fbdev/core/fbcon_ud.c | 28 +++++++++++++++-------------
5 files changed, 55 insertions(+), 46 deletions(-)
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 4838df192ffe..df3fdaf392a6 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -22,12 +22,13 @@
/*
* Accelerated handlers.
*/
-static void update_attr(u8 *dst, const u8 *src, int attribute, struct vc_data *vc)
+static void update_attr(unsigned char *dst, const unsigned char *src, int attribute,
+ struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = DIV_ROUND_UP(vc->vc_font.width, 8);
unsigned int cellsize = vc->vc_font.height * width;
- u8 c;
+ unsigned char c;
offset = cellsize - (offset * width);
for (i = 0; i < cellsize; i++) {
@@ -75,12 +76,13 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
u32 d_pitch, u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf, u8 *dst)
+ struct fb_image *image,
+ unsigned char *buf, u8 *dst)
{
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
unsigned int charcnt = vc->vc_font.charcount;
u32 idx = vc->vc_font.width >> 3;
- const u8 *src;
+ const unsigned char *src;
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
@@ -111,15 +113,15 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
struct fb_info *info, const u16 *s,
u32 attr, u32 cnt, u32 d_pitch,
u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf,
- u8 *dst)
+ struct fb_image *image,
+ unsigned char *buf, u8 *dst)
{
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
unsigned int charcnt = vc->vc_font.charcount;
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
- const u8 *src;
+ const unsigned char *src;
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
@@ -158,7 +160,8 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
u32 buf_align = info->pixmap.buf_align - 1;
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
- u8 *dst, *buf = NULL;
+ unsigned char *buf = NULL;
+ u8 *dst;
image.fg_color = fg;
image.bg_color = bg;
@@ -249,7 +252,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1;
- const u8 *src;
+ const unsigned char *src;
cursor.set = 0;
@@ -267,12 +270,12 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
- par->cursor_state.image.data = src;
+ par->cursor_state.image.data = (const char *)src;
cursor.set |= FB_CUR_SETIMAGE;
}
if (attribute) {
- u8 *dst;
+ unsigned char *dst;
dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
if (!dst)
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 054cf66b15fa..ab78dad15925 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -86,11 +86,11 @@ struct fbcon_par {
int graphics;
bool initialized;
int rotate;
- char *cursor_data;
+ unsigned char *cursor_data;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
struct {
font_data_t *fontdata; /* source font */
- u8 *buf; /* rotated glyphs */
+ unsigned char *buf; /* rotated glyphs */
size_t bufsize;
int buf_rotate; /* rotation of buf */
} rotated;
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 9a9839631cc5..de4a58d3385e 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -23,13 +23,13 @@
* Rotation 270 degrees
*/
-static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
- struct vc_data *vc)
+static void ccw_update_attr(unsigned char *dst, const unsigned char *src, int attribute,
+ struct vc_data *vc)
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = font_glyph_pitch(vc->vc_font.height);
int mod = vc->vc_font.height % 8;
- u8 c, msk = ~(0xff << offset), msk1 = 0;
+ unsigned char c, msk = ~(0xff << offset), msk1 = 0;
if (mod)
msk <<= (8 - mod);
@@ -98,12 +98,13 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
u32 d_pitch, u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf, u8 *dst)
+ struct fb_image *image,
+ unsigned char *buf, u8 *dst)
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
u32 idx = font_glyph_pitch(vc->vc_font.height);
- u8 *src;
+ const unsigned char *src;
while (cnt--) {
src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
@@ -139,8 +140,9 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
u32 buf_align = info->pixmap.buf_align - 1;
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
- u8 *dst, *buf = NULL;
+ unsigned char *buf = NULL;
u32 vyres = GETVYRES(par->p, info);
+ u8 *dst;
if (!par->rotated.buf)
return;
@@ -229,7 +231,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
- char *src;
+ const unsigned char *src;
u32 vyres = GETVYRES(par->p, info);
if (!par->rotated.buf)
@@ -241,14 +243,14 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
attribute = get_attribute(info, c);
src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.width));
- if (par->cursor_state.image.data != src ||
+ if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
- par->cursor_state.image.data = src;
+ par->cursor_state.image.data = (const char *)src;
cursor.set |= FB_CUR_SETIMAGE;
}
if (attribute) {
- u8 *dst;
+ unsigned char *dst;
dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
if (!dst)
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 4cb20337cf79..4e82199082f1 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -23,12 +23,12 @@
* Rotation 90 degrees
*/
-static void cw_update_attr(u8 *dst, u8 *src, int attribute,
- struct vc_data *vc)
+static void cw_update_attr(unsigned char *dst, const unsigned char *src, int attribute,
+ struct vc_data *vc)
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = font_glyph_pitch(vc->vc_font.height);
- u8 c, msk = ~(0xff >> offset);
+ unsigned char c, msk = ~(0xff >> offset);
for (i = 0; i < vc->vc_font.width; i++) {
for (j = 0; j < width; j++) {
@@ -83,12 +83,13 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
u32 d_pitch, u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf, u8 *dst)
+ struct fb_image *image,
+ unsigned char *buf, u8 *dst)
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
u32 idx = font_glyph_pitch(vc->vc_font.height);
- u8 *src;
+ const unsigned char *src;
while (cnt--) {
src = par->rotated.buf + (scr_readw(s++) & charmask) * cellsize;
@@ -124,8 +125,9 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
u32 buf_align = info->pixmap.buf_align - 1;
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
- u8 *dst, *buf = NULL;
+ unsigned char *buf = NULL;
u32 vxres = GETVXRES(par->p, info);
+ u8 *dst;
if (!par->rotated.buf)
return;
@@ -212,7 +214,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
- char *src;
+ const unsigned char *src;
u32 vxres = GETVXRES(par->p, info);
if (!par->rotated.buf)
@@ -224,14 +226,14 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
attribute = get_attribute(info, c);
src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.width));
- if (par->cursor_state.image.data != src ||
+ if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
- par->cursor_state.image.data = src;
+ par->cursor_state.image.data = (const char *)src;
cursor.set |= FB_CUR_SETIMAGE;
}
if (attribute) {
- u8 *dst;
+ unsigned char *dst;
dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
if (!dst)
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index ac22b9846b79..dc48e19513a1 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -22,13 +22,13 @@
* Rotation 180 degrees
*/
-static void ud_update_attr(u8 *dst, u8 *src, int attribute,
- struct vc_data *vc)
+static void ud_update_attr(unsigned char *dst, const unsigned char *src, int attribute,
+ struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = font_glyph_pitch(vc->vc_font.width);
unsigned int cellsize = vc->vc_font.height * width;
- u8 c;
+ unsigned char c;
offset = offset * width;
@@ -84,12 +84,13 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
u32 d_pitch, u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf, u8 *dst)
+ struct fb_image *image,
+ unsigned char *buf, u8 *dst)
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
u32 idx = vc->vc_font.width >> 3;
- u8 *src;
+ const unsigned char *src;
while (cnt--) {
src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
@@ -116,15 +117,15 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
struct fb_info *info, const u16 *s,
u32 attr, u32 cnt, u32 d_pitch,
u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf,
- u8 *dst)
+ struct fb_image *image,
+ unsigned char *buf, u8 *dst)
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
- u8 *src;
+ const unsigned char *src;
while (cnt--) {
src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
@@ -160,9 +161,10 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
u32 buf_align = info->pixmap.buf_align - 1;
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
- u8 *dst, *buf = NULL;
+ unsigned char *buf = NULL;
u32 vyres = GETVYRES(par->p, info);
u32 vxres = GETVXRES(par->p, info);
+ u8 *dst;
if (!par->rotated.buf)
return;
@@ -258,7 +260,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
- char *src;
+ const unsigned char *src;
u32 vyres = GETVYRES(par->p, info);
u32 vxres = GETVXRES(par->p, info);
@@ -271,14 +273,14 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
attribute = get_attribute(info, c);
src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.height));
- if (par->cursor_state.image.data != src ||
+ if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
- par->cursor_state.image.data = src;
+ par->cursor_state.image.data = (const char *)src;
cursor.set |= FB_CUR_SETIMAGE;
}
if (attribute) {
- u8 *dst;
+ unsigned char *dst;
dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
if (!dst)
--
2.56.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/6] lib/fonts: Provide internal helpers for allocating font_data_t
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 1/6] fbcon: Use unsigned char for glyph data Thomas Zimmermann
@ 2026-10-27 13:27 ` Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 3/6] lib/fonts, fbcon: Use font_data_t for rotated fonts Thomas Zimmermann
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Factor out the allocation code for font_data_t from font import in
font_data_import(). Retrieve a writable glyph buffer from the new
helper __font_data_wrbuf().
Having the allocation code in separate functions makes it available
for font rotation and maybe other font utilities. The _wrbuf() helper
returns a writable glyph buffer. Font data is only readable in general.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
lib/fonts/font.h | 12 +++++++++
lib/fonts/fonts.c | 63 ++++++++++++++++++++++++++++++-----------------
2 files changed, 52 insertions(+), 23 deletions(-)
diff --git a/lib/fonts/font.h b/lib/fonts/font.h
index 4f1adf0b6b54..eae8c563f148 100644
--- a/lib/fonts/font.h
+++ b/lib/fonts/font.h
@@ -4,6 +4,7 @@
#define _LIB_FONTS_FONT_H
#include <linux/font.h>
+#include <linux/types.h>
/*
* Font data
@@ -16,6 +17,17 @@ struct font_data {
unsigned char data[];
} __packed;
+/*
+ * font_data_t and helpers
+ */
+
+static inline unsigned char *__font_data_wrbuf(font_data_t *fd)
+{
+ return (unsigned char *)fd;
+}
+
+font_data_t *__font_data_alloc(unsigned int size, gfp_t flags);
+
/*
* Built-in fonts
*/
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 4fc66722d00d..e66a5b6fc3bb 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -47,6 +47,39 @@ static bool font_data_is_internal(font_data_t *fd)
return !REFCOUNT(fd); /* internal fonts have no reference counting */
}
+font_data_t *__font_data_alloc(unsigned int size, gfp_t flags)
+{
+ unsigned int alloc_size;
+ struct font_data *font_data;
+ font_data_t *fd;
+
+ /* Check for overflow in allocation size calculation */
+ if (check_add_overflow(sizeof(*font_data), size, &alloc_size))
+ return ERR_PTR(-EINVAL);
+
+ font_data = kzalloc(alloc_size, flags);
+ if (!font_data)
+ return ERR_PTR(-ENOMEM);
+
+ fd = font_data->data;
+ REFCOUNT(fd) = 1; /* start with reference acquired */
+ FNTSIZE(fd) = size;
+
+ return fd;
+}
+
+static font_data_t *font_data_alloc(unsigned int pitch, unsigned int h, unsigned int charcount)
+{
+ unsigned int size;
+
+ /* Check for integer overflow in font-size calculation */
+ if (check_mul_overflow(h, pitch, &size) ||
+ check_mul_overflow(size, charcount, &size))
+ return ERR_PTR(-EINVAL);
+
+ return __font_data_alloc(size, GFP_USER);
+}
+
static void font_data_free(font_data_t *fd)
{
kfree(to_font_data_struct(fd));
@@ -75,36 +108,20 @@ font_data_t *font_data_import(const struct console_font *font, unsigned int vpit
unsigned int h = font->height;
unsigned int charcount = font->charcount;
const unsigned char *data = font->data;
- u32 csum = 0;
- struct font_data *font_data;
- int size, alloc_size;
+ unsigned char *font_data;
unsigned int i;
font_data_t *fd;
- /* Check for integer overflow in font-size calculation */
- if (check_mul_overflow(h, pitch, &size) ||
- check_mul_overflow(size, charcount, &size))
- return ERR_PTR(-EINVAL);
-
- /* Check for overflow in allocation size calculation */
- if (check_add_overflow(sizeof(*font_data), size, &alloc_size))
- return ERR_PTR(-EINVAL);
-
- font_data = kmalloc(alloc_size, GFP_USER);
- if (!font_data)
- return ERR_PTR(-ENOMEM);
- memset(font_data->extra, 0, sizeof(font_data->extra));
+ fd = font_data_alloc(pitch, h, charcount);
+ if (IS_ERR(fd))
+ return fd;
+ font_data = __font_data_wrbuf(fd);
for (i = 0; i < charcount; ++i)
- memcpy(font_data->data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
+ memcpy(font_data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
if (calc_csum)
- csum = calc_csum(0, font_data->data, size);
-
- fd = font_data->data;
- REFCOUNT(fd) = 1; /* start with reference acquired */
- FNTSIZE(fd) = size;
- FNTSUM(fd) = csum;
+ FNTSUM(fd) = calc_csum(0, font_data, FNTSIZE(fd));
return fd;
}
--
2.56.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/6] lib/fonts, fbcon: Use font_data_t for rotated fonts
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 1/6] fbcon: Use unsigned char for glyph data Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 2/6] lib/fonts: Provide internal helpers for allocating font_data_t Thomas Zimmermann
@ 2026-10-27 13:27 ` Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 4/6] fbcon: Refactor size calculation for cursor buffers Thomas Zimmermann
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Return rotated font data as font_data_t instead of unsigned char*.
Release the data with font_data_put() in fbcon.
It is still possible to use preallocated font buffers for the rotated
font data. The font data tracks the buffer size and reference count to
do so; font_data_rotate() invokes __font_data_alloc() to allocate a
new font-data buffer is necessary.
Returning rotated font data as font_data_t further allows for using
regular font-data helpers on it. Fbcon now manages buffer life time
with the font data's reference counting. Removes the plain kfree().
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/fbcon.c | 3 ++-
drivers/video/fbdev/core/fbcon.h | 3 +--
drivers/video/fbdev/core/fbcon_rotate.c | 19 ++++++++-------
include/linux/font.h | 5 ++--
lib/fonts/font_rotate.c | 32 ++++++++++---------------
5 files changed, 28 insertions(+), 34 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index d97d94bb8e99..9a88a47fc84c 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -770,7 +770,8 @@ static void fbcon_release(struct fb_info *info)
kfree(par->cursor_data);
kfree(par->cursor_src);
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
- kfree(par->rotated.buf);
+ if (par->rotated.buf)
+ font_data_put(par->rotated.buf);
#endif
kfree(info->fbcon_par);
info->fbcon_par = NULL;
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index ab78dad15925..8b662226004c 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -90,8 +90,7 @@ struct fbcon_par {
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
struct {
font_data_t *fontdata; /* source font */
- unsigned char *buf; /* rotated glyphs */
- size_t bufsize;
+ font_data_t *buf; /* rotated font */
int buf_rotate; /* rotation of buf */
} rotated;
#endif
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 6cdbc96eeca6..b7c48e7c4a6e 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -18,7 +18,7 @@
int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
{
struct fbcon_par *par = info->fbcon_par;
- unsigned char *buf;
+ font_data_t *buf;
int ret;
if (par->p->fontdata == par->rotated.fontdata && par->rotate == par->rotated.buf_rotate)
@@ -32,21 +32,22 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
buf = font_data_rotate(par->rotated.fontdata, vc->vc_font.width,
vc->vc_font.height, vc->vc_font.charcount,
- par->rotated.buf_rotate, par->rotated.buf,
- &par->rotated.bufsize);
+ par->rotated.buf_rotate, par->rotated.buf);
if (IS_ERR(buf)) {
ret = PTR_ERR(buf);
- goto err_kfree;
+ goto err_font_data_put;
}
+ if (par->rotated.buf)
+ font_data_put(par->rotated.buf);
par->rotated.buf = buf;
return 0;
-err_kfree:
- kfree(par->rotated.buf);
- par->rotated.buf = NULL; /* clear here to avoid output */
- par->rotated.bufsize = 0;
-
+err_font_data_put:
+ if (par->rotated.buf) {
+ font_data_put(par->rotated.buf);
+ par->rotated.buf = NULL; /* clear here to avoid output */
+ }
return ret;
}
diff --git a/include/linux/font.h b/include/linux/font.h
index be1a26ff8ae9..2d7e2ca3db0f 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -120,9 +120,8 @@ void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsig
unsigned char *out);
void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
unsigned char *out);
-unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
- unsigned int charcount, unsigned int steps,
- unsigned char *buf, size_t *bufsize);
+font_data_t *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
+ unsigned int charcount, unsigned int steps, font_data_t *buf);
/*
* Font description
diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c
index 275406008823..ea54bd618ffb 100644
--- a/lib/fonts/font_rotate.c
+++ b/lib/fonts/font_rotate.c
@@ -181,8 +181,7 @@ EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
* @height: The number of scanlines in the glyph
* @charcount: The number of glyphs in the font
* @steps: Number of rotation steps of 90°
- * @buf: Preallocated output buffer; can be NULL
- * @bufsize: The size of @buf in bytes; can be NULL
+ * @buf: Preallocated font data; can be NULL
*
* The parameters @width and @height refer to the visible number of pixels
* and scanlines in a single glyph. The number of glyphs is given in @charcount.
@@ -194,16 +193,14 @@ EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
* as returned by font_data_buf(). Callers are responsible to free the returned
* buffer with kfree(). Font rotation typically happens when displays get
* re-oriented. To avoid unnecessary re-allocation of the memory buffer, the
- * caller can pass in an earlier result buffer in @buf for reuse. The old and
- * new buffer sizes are given and retrieved by the caller in @bufsize. The
- * allocation semantics are compatible with krealloc().
+ * caller can pass in an earlier result in @buf for reuse. The returned font
+ * data should be released with font_data_put().
*
* Returns:
- * A buffer with rotated glyphs on success, or an error pointer otherwise
+ * Font data with rotated glyphs on success, or an error pointer otherwise
*/
-unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
- unsigned int charcount, unsigned int steps,
- unsigned char *buf, size_t *bufsize)
+font_data_t *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
+ unsigned int charcount, unsigned int steps, font_data_t *buf)
{
const unsigned char *src = font_data_buf(fd);
unsigned int s_cellsize = font_glyph_size(width, height);
@@ -227,19 +224,16 @@ unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned in
if (check_mul_overflow(charcount, d_cellsize, &size))
return ERR_PTR(-EINVAL);
- if (!buf || !bufsize || size > *bufsize) {
- dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL);
- if (!dst)
- return ERR_PTR(-ENOMEM);
-
- kfree(buf);
- buf = dst;
- if (bufsize)
- *bufsize = size;
+ if (!buf || size > font_data_size(buf)) {
+ buf = __font_data_alloc(size, GFP_KERNEL);
+ if (IS_ERR(buf))
+ return buf;
} else {
- dst = buf;
+ font_data_get(buf);
}
+ dst = __font_data_wrbuf(buf);
+
switch (steps) {
case 0:
memcpy(dst, src, size);
--
2.56.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/6] fbcon: Refactor size calculation for cursor buffers
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
` (2 preceding siblings ...)
2026-10-27 13:27 ` [PATCH 3/6] lib/fonts, fbcon: Use font_data_t for rotated fonts Thomas Zimmermann
@ 2026-10-27 13:27 ` Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 5/6] fbcon: Look up glyphs using the font interface Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 6/6] fbcon: Handle characters with no glyph defined in a consistent way Thomas Zimmermann
5 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Replace open-coded size calculation for cursor glyph buffers with
font helpers. Use it for glyph lookup and buffer allocation.
Treat glyph width as bits per scanline instead of bytes. This is
consistent with font helpers.
Note that with screen rotation enabled, width and height swap places
for CW and CCW implementations.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/bitblit.c | 9 ++++++---
drivers/video/fbdev/core/fbcon_ccw.c | 10 ++++++----
drivers/video/fbdev/core/fbcon_cw.c | 10 ++++++----
drivers/video/fbdev/core/fbcon_ud.c | 10 ++++++----
4 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index df3fdaf392a6..65dbdb666ae2 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -248,7 +248,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = DIV_ROUND_UP(vc->vc_font.width, 8), c;
+ int width = vc->vc_font.width;
+ int vpitch = vc->vc_font.height;
+ int cellsize = font_glyph_size(width, vpitch);
+ int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1;
@@ -266,7 +269,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
/* Clamp to font size, same as bit_putcs_aligned() */
if (c >= vc->vc_font.charcount)
c = 0;
- src = vc->vc_font.data + (c * (w * vc->vc_font.height));
+ src = vc->vc_font.data + (c * cellsize);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
@@ -277,7 +280,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (attribute) {
unsigned char *dst;
- dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
+ dst = kmalloc(cellsize, GFP_ATOMIC);
if (!dst)
return;
kfree(par->cursor_data);
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index de4a58d3385e..589291caed32 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -226,7 +226,9 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = font_glyph_pitch(vc->vc_font.height);
+ int width = vc->vc_font.height;
+ int vpitch = vc->vc_font.width;
+ int cellsize = font_glyph_size(width, vpitch);
int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
@@ -241,7 +243,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.width));
+ src = par->rotated.buf + ((c & charmask) * cellsize);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
@@ -252,7 +254,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (attribute) {
unsigned char *dst;
- dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
+ dst = kmalloc(cellsize, GFP_ATOMIC);
if (!dst)
return;
kfree(par->cursor_data);
@@ -304,7 +306,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (!tmp)
return;
- mask = kmalloc_array(vc->vc_font.width, w, GFP_ATOMIC);
+ mask = kmalloc(cellsize, GFP_ATOMIC);
if (!mask) {
kfree(tmp);
return;
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 4e82199082f1..87e9dd666953 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -209,7 +209,9 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = font_glyph_pitch(vc->vc_font.height);
+ int width = vc->vc_font.height;
+ int vpitch = vc->vc_font.width;
+ int cellsize = font_glyph_size(width, vpitch);
int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
@@ -224,7 +226,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.width));
+ src = par->rotated.buf + ((c & charmask) * (cellsize));
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
@@ -235,7 +237,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (attribute) {
unsigned char *dst;
- dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
+ dst = kmalloc(cellsize, GFP_ATOMIC);
if (!dst)
return;
kfree(par->cursor_data);
@@ -287,7 +289,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (!tmp)
return;
- mask = kmalloc_array(vc->vc_font.width, w, GFP_ATOMIC);
+ mask = kmalloc(cellsize, GFP_ATOMIC);
if (!mask) {
kfree(tmp);
return;
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index dc48e19513a1..a610af1023de 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -255,7 +255,9 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = font_glyph_pitch(vc->vc_font.width);
+ int width = vc->vc_font.width;
+ int vpitch = vc->vc_font.height;
+ int cellsize = font_glyph_size(width, vpitch);
int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
@@ -271,7 +273,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.height));
+ src = par->rotated.buf + ((c & charmask) * cellsize);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
@@ -282,7 +284,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (attribute) {
unsigned char *dst;
- dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
+ dst = kmalloc(cellsize, GFP_ATOMIC);
if (!dst)
return;
kfree(par->cursor_data);
@@ -334,7 +336,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
if (!tmp)
return;
- mask = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
+ mask = kmalloc(cellsize, GFP_ATOMIC);
if (!mask) {
kfree(tmp);
return;
--
2.56.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/6] fbcon: Look up glyphs using the font interface
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
` (3 preceding siblings ...)
2026-10-27 13:27 ` [PATCH 4/6] fbcon: Refactor size calculation for cursor buffers Thomas Zimmermann
@ 2026-10-27 13:27 ` Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 6/6] fbcon: Handle characters with no glyph defined in a consistent way Thomas Zimmermann
5 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Replace the open-coded glyph lookup with font_data_glyph_buf() in
implementations of putcs and cursor bitops. As rotated glyphs are
now stored as font_data_t, the regular lookup function for glyphs
works.
Also replace the open-coded size calculations with font-data helpers.
Note that with screen rotation enabled, width and height swap places
for CW and CCW implementations.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/bitblit.c | 23 ++++++++++++++---------
drivers/video/fbdev/core/fbcon_ccw.c | 14 ++++++++------
drivers/video/fbdev/core/fbcon_cw.c | 14 ++++++++------
drivers/video/fbdev/core/fbcon_ud.c | 23 ++++++++++++++---------
4 files changed, 44 insertions(+), 30 deletions(-)
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 65dbdb666ae2..b1c90bc29648 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -75,13 +75,15 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
- u32 d_pitch, u32 s_pitch, u32 cellsize,
+ u32 d_pitch, u32 s_width, u32 s_vpitch,
struct fb_image *image,
unsigned char *buf, u8 *dst)
{
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
unsigned int charcnt = vc->vc_font.charcount;
u32 idx = vc->vc_font.width >> 3;
+ struct fbcon_par *par = info->fbcon_par;
+ u32 s_pitch = font_glyph_pitch(s_width);
const unsigned char *src;
while (cnt--) {
@@ -89,7 +91,7 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
if (ch >= charcnt)
ch = 0;
- src = vc->vc_font.data + (unsigned int)ch * cellsize;
+ src = font_data_glyph_buf(par->p->fontdata, s_width, s_vpitch, ch);
if (attr) {
update_attr(buf, src, attr, vc);
@@ -112,7 +114,7 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
static inline void bit_putcs_unaligned(struct vc_data *vc,
struct fb_info *info, const u16 *s,
u32 attr, u32 cnt, u32 d_pitch,
- u32 s_pitch, u32 cellsize,
+ u32 s_width, u32 s_vpitch,
struct fb_image *image,
unsigned char *buf, u8 *dst)
{
@@ -121,6 +123,8 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
+ struct fbcon_par *par = info->fbcon_par;
+ u32 s_pitch = font_glyph_pitch(s_width);
const unsigned char *src;
while (cnt--) {
@@ -128,7 +132,7 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
if (ch >= charcnt)
ch = 0;
- src = vc->vc_font.data + (unsigned int)ch * cellsize;
+ src = font_data_glyph_buf(par->p->fontdata, s_width, s_vpitch, ch);
if (attr) {
update_attr(buf, src, attr, vc);
@@ -153,8 +157,9 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
int fg, int bg)
{
struct fb_image image;
- u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
- u32 cellsize = width * vc->vc_font.height;
+ u32 width = vc->vc_font.width;
+ u32 vpitch = vc->vc_font.height;
+ u32 cellsize = font_glyph_size(width, vpitch);
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
u32 buf_align = info->pixmap.buf_align - 1;
@@ -192,10 +197,10 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
if (!mod)
bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
- width, cellsize, &image, buf, dst);
+ width, vpitch, &image, buf, dst);
else
bit_putcs_unaligned(vc, info, s, attribute, cnt,
- pitch, width, cellsize, &image,
+ pitch, width, vpitch, &image,
buf, dst);
image.dx += cnt * vc->vc_font.width;
@@ -269,7 +274,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
/* Clamp to font size, same as bit_putcs_aligned() */
if (c >= vc->vc_font.charcount)
c = 0;
- src = vc->vc_font.data + (c * cellsize);
+ src = font_data_glyph_buf(par->p->fontdata, width, vpitch, c);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 589291caed32..9da6c0e41e7a 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -97,7 +97,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
- u32 d_pitch, u32 s_pitch, u32 cellsize,
+ u32 d_pitch, u32 s_width, u32 s_vpitch,
struct fb_image *image,
unsigned char *buf, u8 *dst)
{
@@ -107,7 +107,8 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const unsigned char *src;
while (cnt--) {
- src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
+ scr_readw(s--) & charmask);
if (attr) {
ccw_update_attr(buf, src, attr, vc);
@@ -133,8 +134,9 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
{
struct fb_image image;
struct fbcon_par *par = info->fbcon_par;
- u32 width = font_glyph_pitch(vc->vc_font.height);
- u32 cellsize = width * vc->vc_font.width;
+ u32 width = vc->vc_font.height;
+ u32 vpitch = vc->vc_font.width;
+ u32 cellsize = font_glyph_size(width, vpitch);
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
u32 buf_align = info->pixmap.buf_align - 1;
@@ -176,7 +178,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
dst = fb_get_buffer_offset(info, &info->pixmap, size);
image.data = dst;
ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
- width, cellsize, &image, buf, dst);
+ width, vpitch, &image, buf, dst);
image.dy += image.height;
count -= cnt;
s -= cnt;
@@ -243,7 +245,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->rotated.buf + ((c & charmask) * cellsize);
+ src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 87e9dd666953..354f40f77bb4 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -82,7 +82,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
- u32 d_pitch, u32 s_pitch, u32 cellsize,
+ u32 d_pitch, u32 s_width, u32 s_vpitch,
struct fb_image *image,
unsigned char *buf, u8 *dst)
{
@@ -92,7 +92,8 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const unsigned char *src;
while (cnt--) {
- src = par->rotated.buf + (scr_readw(s++) & charmask) * cellsize;
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
+ scr_readw(s++) & charmask);
if (attr) {
cw_update_attr(buf, src, attr, vc);
@@ -118,8 +119,9 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
{
struct fb_image image;
struct fbcon_par *par = info->fbcon_par;
- u32 width = font_glyph_pitch(vc->vc_font.height);
- u32 cellsize = width * vc->vc_font.width;
+ u32 width = vc->vc_font.height;
+ u32 vpitch = vc->vc_font.width;
+ u32 cellsize = font_glyph_size(width, vpitch);
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
u32 buf_align = info->pixmap.buf_align - 1;
@@ -159,7 +161,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
dst = fb_get_buffer_offset(info, &info->pixmap, size);
image.data = dst;
cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
- width, cellsize, &image, buf, dst);
+ width, vpitch, &image, buf, dst);
image.dy += image.height;
count -= cnt;
s += cnt;
@@ -226,7 +228,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->rotated.buf + ((c & charmask) * (cellsize));
+ src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index a610af1023de..01f45eaa2013 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -83,17 +83,19 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
const u16 *s, u32 attr, u32 cnt,
- u32 d_pitch, u32 s_pitch, u32 cellsize,
+ u32 d_pitch, u32 s_width, u32 s_vpitch,
struct fb_image *image,
unsigned char *buf, u8 *dst)
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
u32 idx = vc->vc_font.width >> 3;
+ u32 s_pitch = font_glyph_pitch(s_width);
const unsigned char *src;
while (cnt--) {
- src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
+ scr_readw(s--) & charmask);
if (attr) {
ud_update_attr(buf, src, attr, vc);
@@ -116,7 +118,7 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
static inline void ud_putcs_unaligned(struct vc_data *vc,
struct fb_info *info, const u16 *s,
u32 attr, u32 cnt, u32 d_pitch,
- u32 s_pitch, u32 cellsize,
+ u32 s_width, u32 s_vpitch,
struct fb_image *image,
unsigned char *buf, u8 *dst)
{
@@ -125,10 +127,12 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
+ u32 s_pitch = font_glyph_pitch(s_width);
const unsigned char *src;
while (cnt--) {
- src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
+ scr_readw(s--) & charmask);
if (attr) {
ud_update_attr(buf, src, attr, vc);
@@ -154,8 +158,9 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
{
struct fb_image image;
struct fbcon_par *par = info->fbcon_par;
- u32 width = font_glyph_pitch(vc->vc_font.width);
- u32 cellsize = width * vc->vc_font.height;
+ u32 width = vc->vc_font.width;
+ u32 vpitch = vc->vc_font.height;
+ u32 cellsize = font_glyph_size(width, vpitch);
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
u32 buf_align = info->pixmap.buf_align - 1;
@@ -200,10 +205,10 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
if (!mod)
ud_putcs_aligned(vc, info, s, attribute, cnt, pitch,
- width, cellsize, &image, buf, dst);
+ width, vpitch, &image, buf, dst);
else
ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch,
- width, cellsize, &image,
+ width, vpitch, &image,
buf, dst);
image.dx += image.width;
@@ -273,7 +278,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->rotated.buf + ((c & charmask) * cellsize);
+ src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
--
2.56.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6/6] fbcon: Handle characters with no glyph defined in a consistent way
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
` (4 preceding siblings ...)
2026-10-27 13:27 ` [PATCH 5/6] fbcon: Look up glyphs using the font interface Thomas Zimmermann
@ 2026-10-27 13:27 ` Thomas Zimmermann
5 siblings, 0 replies; 7+ messages in thread
From: Thomas Zimmermann @ 2026-10-27 13:27 UTC (permalink / raw)
To: deller, simona; +Cc: dri-devel, linux-fbdev, sashiko-reviews, Thomas Zimmermann
Check the result of font_data_glyph_buf() for NULL when drawing the
screen. Fall back to a default value of '\0' for undefined glpyhs. Skip
the character if no fallback exists.
Error checking for fonts has been inconsistent or absent from fbcon.
Most of the drawing code relies on earlier validation in the font-import
code. Some code implements the glyph test by itself. At least all of
fbcon should be consistent in how it handles undefined glyphs.
Calls to font_data_glyph_buf() returning NULL for undefined glyphs make
it easy to handle this special case consistently across fbcon.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/video/fbdev/core/bitblit.c | 27 +++++++++++++++++----------
drivers/video/fbdev/core/fbcon_ccw.c | 12 +++++++++++-
drivers/video/fbdev/core/fbcon_cw.c | 13 +++++++++++--
drivers/video/fbdev/core/fbcon_ud.c | 18 +++++++++++++++++-
4 files changed, 56 insertions(+), 14 deletions(-)
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index b1c90bc29648..e108cd50cb1d 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -80,7 +80,6 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
unsigned char *buf, u8 *dst)
{
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- unsigned int charcnt = vc->vc_font.charcount;
u32 idx = vc->vc_font.width >> 3;
struct fbcon_par *par = info->fbcon_par;
u32 s_pitch = font_glyph_pitch(s_width);
@@ -89,9 +88,12 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
- if (ch >= charcnt)
- ch = 0;
src = font_data_glyph_buf(par->p->fontdata, s_width, s_vpitch, ch);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch, '\0');
+ if (!src)
+ goto next_char;
+ }
if (attr) {
update_attr(buf, src, attr, vc);
@@ -104,7 +106,7 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
else
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
image->height);
-
+next_char:
dst += s_pitch;
}
@@ -119,7 +121,6 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
unsigned char *buf, u8 *dst)
{
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- unsigned int charcnt = vc->vc_font.charcount;
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
@@ -130,9 +131,12 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
- if (ch >= charcnt)
- ch = 0;
src = font_data_glyph_buf(par->p->fontdata, s_width, s_vpitch, ch);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch, '\0');
+ if (!src)
+ goto next_char;
+ }
if (attr) {
update_attr(buf, src, attr, vc);
@@ -142,6 +146,7 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
image->height, shift_high,
shift_low, mod);
+next_char:
shift_low += mod;
dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
shift_low &= 7;
@@ -271,10 +276,12 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
attribute = get_attribute(info, c);
c &= charmask;
- /* Clamp to font size, same as bit_putcs_aligned() */
- if (c >= vc->vc_font.charcount)
- c = 0;
src = font_data_glyph_buf(par->p->fontdata, width, vpitch, c);
+ if (!src) {
+ src = font_data_glyph_buf(par->p->fontdata, width, vpitch, '\0');
+ if (!src)
+ return;
+ }
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 9da6c0e41e7a..cbaa75fc1cc1 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -109,6 +109,11 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
while (cnt--) {
src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
scr_readw(s--) & charmask);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch, '\0');
+ if (!src)
+ goto next_char;
+ }
if (attr) {
ccw_update_attr(buf, src, attr, vc);
@@ -121,7 +126,7 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
else
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
vc->vc_font.width);
-
+next_char:
dst += d_pitch * vc->vc_font.width;
}
@@ -246,6 +251,11 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
+ if (!src)
+ return;
+ }
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 354f40f77bb4..7606ad38c269 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -94,7 +94,11 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
while (cnt--) {
src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
scr_readw(s++) & charmask);
-
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch, '\0');
+ if (!src)
+ goto next_char;
+ }
if (attr) {
cw_update_attr(buf, src, attr, vc);
src = buf;
@@ -106,7 +110,7 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
else
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
vc->vc_font.width);
-
+next_char:
dst += d_pitch * vc->vc_font.width;
}
@@ -229,6 +233,11 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, width, vpitch, '\0');
+ if (!src)
+ return;
+ }
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 01f45eaa2013..bdba3a959d1e 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -96,6 +96,11 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
while (cnt--) {
src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
scr_readw(s--) & charmask);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch, '\0');
+ if (!src)
+ goto next_char;
+ }
if (attr) {
ud_update_attr(buf, src, attr, vc);
@@ -108,7 +113,7 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
else
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
image->height);
-
+next_char:
dst += s_pitch;
}
@@ -133,6 +138,11 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
while (cnt--) {
src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch,
scr_readw(s--) & charmask);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, s_width, s_vpitch, '\0');
+ if (!src)
+ goto next_char;
+ }
if (attr) {
ud_update_attr(buf, src, attr, vc);
@@ -142,6 +152,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
image->height, shift_high,
shift_low, mod);
+next_char:
shift_low += mod;
dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
shift_low &= 7;
@@ -279,6 +290,11 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = font_data_glyph_buf(par->rotated.buf, width, vpitch, c & charmask);
+ if (!src) {
+ src = font_data_glyph_buf(par->rotated.buf, width, vpitch, '\0');
+ if (!src)
+ return;
+ }
if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
--
2.56.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-27 13:36 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-27 13:27 [PATCH 0/6] fbcon: Clean up glyph handling on redraws Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 1/6] fbcon: Use unsigned char for glyph data Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 2/6] lib/fonts: Provide internal helpers for allocating font_data_t Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 3/6] lib/fonts, fbcon: Use font_data_t for rotated fonts Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 4/6] fbcon: Refactor size calculation for cursor buffers Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 5/6] fbcon: Look up glyphs using the font interface Thomas Zimmermann
2026-10-27 13:27 ` [PATCH 6/6] fbcon: Handle characters with no glyph defined in a consistent way Thomas Zimmermann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox