From: Alan Mackenzie <acm@muc.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Jiri Slaby <jirislaby@kernel.org>,
Simona Vetter <simona@ffwll.ch>,
linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org,
Helge Deller <deller@gmx.de>,
Thomas Zimmermann <tzimmermann@suse.de>,
linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org
Cc: acm@muc.de
Subject: [Patch 2/9]: Glyph size: Use GLYPH_SZ/HW rather than hardcoded 2, 1
Date: Thu, 27 Aug 2026 18:45:05 +0000 [thread overview]
Message-ID: <apCFsX_JXJ9m3vpr@MAC.fritz.box> (raw)
In-Reply-To: <apCEDM2sWv_M354-@MAC.fritz.box>
vt: 32b glyph: 2. Use GLYPH_SZ, GLYPH_HW rather than hardcoded 2, 1.
These #defines enable the console to be built for either 16-bit or
32-bit glyphs.
Signed-off-by: Alan Mackenzie <acm@muc.de>
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 13f4e48b4142..18affdb3c7c5 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -53,8 +55,8 @@
/* set reverse video on characters s-e of console with selection. */
static inline void highlight(const int s, const int e)
{
- invert_screen(vc_sel.cons, s, e-s+2, true);
+ invert_screen(vc_sel.cons, s, e-s + GLYPH_SZ, true);
}
/* use complementary color to show the pointer */
@@ -67,7 +69,7 @@ static u32
sel_pos(int n, bool unicode)
{
if (unicode)
- return screen_glyph_unicode(vc_sel.cons, n / 2);
+ return screen_glyph_unicode(vc_sel.cons, n / GLYPH_SZ);
return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n),
false);
}
@@ -136,7 +138,7 @@ int sel_loadlut(u32 __user *lut)
/* does screen address p correspond to character at LH/RH edge of screen? */
static inline int atedge(const int p, int size_row)
{
- return (!(p % size_row) || !((p + 2) % size_row));
+ return (!(p % size_row) || !((p + GLYPH_SZ) % size_row));
}
/* stores the char in UTF8 and returns the number of bytes used (1-4) */
@@ -214,8 +216,8 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
/* Allocate a new buffer before freeing the old one ... */
/* chars can take up to 4 bytes with unicode */
- bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1,
- GFP_KERNEL | __GFP_NOWARN);
+ bp = kmalloc_array((vc_sel.end - vc_sel.start) / GLYPH_SZ + 1,
+ unicode ? 4 : 1, GFP_KERNEL | __GFP_NOWARN);
if (!bp) {
printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection();
@@ -225,7 +227,7 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
vc_sel.buffer = bp;
obp = bp;
- for (i = vc_sel.start; i <= vc_sel.end; i += 2) {
+ for (i = vc_sel.start; i <= vc_sel.end; i += GLYPH_SZ) {
u32 c = sel_pos(i, unicode);
if (unicode)
bp += store_utf8(c, bp);
@@ -233,7 +235,7 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
*bp++ = c;
if (!is_space_on_vt(c))
obp = bp;
- if (!((i + 2) % vc->vc_size_row)) {
+ if (!((i + GLYPH_SZ) % size_row)) {
/* strip trailing blanks from line and add newline,
unless non-space at end of line. */
if (obp != bp) {
@@ -261,7 +263,7 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
break;
case TIOCL_SELWORD: /* word-by-word selection */
spc = is_space_on_vt(sel_pos(ps, unicode));
- for (new_sel_start = ps; ; ps -= 2) {
+ for (new_sel_start = ps; ; ps -= GLYPH_SZ) {
if ((spc && !is_space_on_vt(sel_pos(ps, unicode))) ||
(!spc && !inword(sel_pos(ps, unicode))))
break;
@@ -271,19 +273,19 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
}
spc = is_space_on_vt(sel_pos(pe, unicode));
- for (new_sel_end = pe; ; pe += 2) {
+ for (new_sel_end = pe; ; pe += GLYPH_SZ) {
if ((spc && !is_space_on_vt(sel_pos(pe, unicode))) ||
(!spc && !inword(sel_pos(pe, unicode))))
break;
new_sel_end = pe;
- if (!((pe + 2) % vc->vc_size_row))
+ if (!((pe + GLYPH_SZ) % size_row))
break;
}
break;
case TIOCL_SELLINE: /* line-by-line selection */
- new_sel_start = rounddown(ps, vc->vc_size_row);
- new_sel_end = rounddown(pe, vc->vc_size_row) +
- vc->vc_size_row - 2;
+ new_sel_start = rounddown(ps, size_row);
+ new_sel_end = rounddown(pe, size_row) +
+ size_row - GLYPH_SZ;
break;
case TIOCL_SELPOINTER:
highlight_pointer(pe);
@@ -298,8 +300,8 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
!atedge(new_sel_end, vc->vc_size_row) &&
- is_space_on_vt(sel_pos(new_sel_end, unicode))) {
- for (pe = new_sel_end + 2; ; pe += 2)
+ is_space_on_vt(sel_pos(new_sel_end, unicode))) {
+ for (pe = new_sel_end + GLYPH_SZ; ; pe += GLYPH_SZ)
if (!is_space_on_vt(sel_pos(pe, unicode)) ||
atedge(pe, vc->vc_size_row))
break;
@@ -313,16 +315,16 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
if (new_sel_end == vc_sel.end) /* no action required */
return 0;
else if (new_sel_end > vc_sel.end) /* extend to right */
- highlight(vc_sel.end + 2, new_sel_end);
+ highlight(vc_sel.end + GLYPH_SZ, new_sel_end);
else /* contract from right */
- highlight(new_sel_end + 2, vc_sel.end);
+ highlight(new_sel_end + GLYPH_SZ, vc_sel.end);
}
else if (new_sel_end == vc_sel.end)
{
if (new_sel_start < vc_sel.start) /* extend to left */
- highlight(new_sel_start, vc_sel.start - 2);
+ highlight(new_sel_start, vc_sel.start - GLYPH_SZ);
else /* contract from left */
- highlight(vc_sel.start, new_sel_start - 2);
+ highlight(vc_sel.start, new_sel_start - GLYPH_SZ);
}
else /* some other case; start selection from scratch */
{
@@ -360,8 +363,8 @@ static int vc_selection(struct vc_data *vc, struct tiocl_selection *v,
return 0;
}
- ps = v->ys * vc->vc_size_row + (v->xs << 1);
- pe = v->ye * vc->vc_size_row + (v->xe << 1);
+ ps = v->ys * size_row + (v->xs * GLYPH_SZ);
+ pe = v->ye * size_row + (v->xe * GLYPH_SZ);
if (ps > pe) /* make vc_sel.start <= vc_sel.end */
swap(ps, pe);
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 7d40eacc21b3..f23d61fe10c1 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -213,16 +215,15 @@ static int vcs_size(const struct vc_data *vc, bool attr, bool unicode)
WARN_CONSOLE_UNLOCKED();
- size = vc->vc_rows * vc->vc_cols;
-
- if (attr) {
- if (unicode)
- return -EOPNOTSUPP;
-
- size = 2 * size + HEADER_SIZE;
- } else if (unicode)
- size *= 4;
-
+ if (attr && unicode)
+ return -EOPNOTSUPP;
+ else if (unicode)
+ size = (vc->vc_rows * vc->vc_cols) * 4;
+ else if (attr)
+ size = (vc->vc_rows * vc->vc_cols) * GLYPH_SZ +
+ HEADER_SIZE;
+ else
+ size = (vc->vc_rows * vc->vc_cols);
return size;
}
@@ -283,7 +288,8 @@ static void vcs_read_buf_noattr(const struct vc_data *vc, char *con_buf,
pos += maxcol - col;
while (count-- > 0) {
- *con_buf++ = (vcs_scr_readw(vc, org++) & 0xff);
+ *con_buf++ = (vcs_scr_readw(vc, org) & 0xff);
+ org += GLYPH_HW;
if (++col == maxcol) {
org = screen_pos(vc, pos, viewed);
col = 0;
@@ -298,6 +304,7 @@ static unsigned int vcs_read_buf(const struct vc_data *vc, char *con_buf,
{
u16 *org, *con_buf16;
unsigned int col, maxcol = vc->vc_cols;
+ unsigned int sz = GLYPH_SZ;
unsigned int filled = count;
if (pos < HEADER_SIZE) {
@@ -315,40 +324,60 @@ static unsigned int vcs_read_buf(const struct vc_data *vc, char *con_buf,
/* Advance state pointers and move on. */
count -= min(HEADER_SIZE, count);
+ /* COUNT is now a count of the number of bytes after the
+ * header to be read.
+ */
pos = HEADER_SIZE;
con_buf += HEADER_SIZE;
/* If count >= 0, then pos is even... */
- } else if (pos & 1) {
+ } else if (pos & (sz - 1)) {
/*
- * Skip first byte for output if start address is odd. Update
- * region sizes up/down depending on free space in buffer.
+ * Skip any unaligned bytes for output if the start address
+ * is not on a glyph boundary. Update region sizes up/down
+ * depending on free space in buffer.
+ */
+ (*skip) += (pos & (sz - 1));
+ if (count + (pos & (sz - 1)) <= CON_BUF_SIZE)
+ count += (pos & (sz - 1));
+ /* COUNT is now the number of bytes to be read starting at
+ * the whole character at or before POS.
*/
- (*skip)++;
- if (count < CON_BUF_SIZE)
- count++;
else
- filled--;
+ filled -= (pos & (sz - 1));
}
if (!count)
return filled;
pos -= HEADER_SIZE;
- pos /= 2;
+ pos /= sz;
col = pos % maxcol;
org = screen_pos(vc, pos, viewed);
pos += maxcol - col;
+ /* From now on, POS is the offset from the start of the screen in
+ * characters of the next end of line.
+ */
/*
* Buffer has even length, so we can always copy character + attribute.
- * We do not copy last byte to userspace if count is odd.
+ * We will not copy unaligned last bytes to userspace if count is not a
+ * multiple of SZ.
+ */
+ count = (count + sz - 1) / sz;
+ /* COUNT is now the number of screen characters to read, including any
+ * leading/trailing bytes which the caller will discard.
*/
- count = (count + 1) / 2;
con_buf16 = (u16 *)con_buf;
while (count) {
- *con_buf16++ = vcs_scr_readw(vc, org++);
+#ifdef CONFIG_FB_GLYPH_21BIT
+ *(u32 *)con_buf16 = vcs_scr_readw(vc, org);
+#else
+ *con_buf16 = vcs_scr_readw(vc, org);
+#endif
+ con_buf16 += GLYPH_HW;
+ org += GLYPH_HW;
count--;
if (++col == maxcol) {
org = screen_pos(vc, pos, viewed);
@@ -481,12 +514,15 @@ static u16 *vcs_write_buf_noattr(struct vc_data *vc, const char *con_buf,
pos += maxcol - col;
while (count > 0) {
- unsigned char c = *con_buf++;
+ unsigned int c;
+ c = *con_buf++;
count--;
vcs_scr_writew(vc,
- (vcs_scr_readw(vc, org) & 0xff00) | c, org);
- org++;
+ ((vcs_scr_readw(vc, org) & ~0xffu) |
+ (c & 0xff)),
+ org);
+ org += GLYPH_HW;
if (++col == maxcol) {
org = screen_pos(vc, pos, viewed);
col = 0;
@@ -534,35 +560,55 @@ static u16 *vcs_write_buf(struct vc_data *vc, const char *con_buf,
return NULL;
pos -= HEADER_SIZE;
- col = (pos/2) % maxcol;
+ col = (pos / sz) % maxcol;
- *org0 = org = screen_pos(vc, pos/2, viewed);
+ *org0 = org = screen_pos(vc, pos / sz, viewed);
- /* odd pos -- the first single character */
- if (pos & 1) {
- count--;
- c = *con_buf++;
- vcs_scr_writew(vc, vc_compile_le16(c, vcs_scr_readw(vc, org)),
- org);
- org++;
- pos++;
+ /* Unaligned bytes at start of buffer */
+ if (pos & (sz - 1)) {
+ u32 old_char = vcs_scr_readw(vc, org);
+ u32 new_char = 0;
+ int old_bytes = pos & (sz - 1);
+
+ for (i = 0; i < sz; i++, old_char >>= 8)
+ lo_to_hi[i] = old_char & 0xff;
+ for (i = old_bytes; i < sz && count; i++, count--) {
+ c = *con_buf++;
+ pos++;
+#ifdef __BIG_ENDIAN
+ lo_to_hi[sz - i - 1] = c;
+#else
+ lo_to_hi[i] = c;
+#endif
+ }
+ for (i = sz - 1; i >= 0; i--) {
+ new_char <<= 8;
+ new_char |= lo_to_hi[i];
+ }
+ vcs_scr_writew(vc, new_char, org);
+ org += GLYPH_HW;
if (++col == maxcol) {
- org = screen_pos(vc, pos/2, viewed);
+ org = screen_pos(vc, pos / sz, viewed);
col = 0;
}
}
- pos /= 2;
+ pos /= sz;
pos += maxcol - col;
- /* even pos -- handle attr+character pairs */
- while (count > 1) {
- unsigned short w;
+ /* aligned pos -- handle attr+character pairs */
+ while (count >= sz) {
+ unsigned int w;
+#ifdef CONFIG_FB_GLYPH_21BIT
+ w = get_unaligned(((unsigned int *)con_buf));
+#else
w = get_unaligned(((unsigned short *)con_buf));
- vcs_scr_writew(vc, w, org++);
- con_buf += 2;
- count -= 2;
+#endif
+ vcs_scr_writew(vc, w, org);
+ org += GLYPH_HW;
+ con_buf += sz;
+ count -= sz;
if (++col == maxcol) {
org = screen_pos(vc, pos, viewed);
col = 0;
@@ -592,6 +654,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
ssize_t ret;
loff_t pos;
bool viewed, attr;
+ int unaligned_before;
if (use_unicode(inode))
return -EOPNOTSUPP;
@@ -620,12 +683,29 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (count > size - pos)
count = size - pos;
written = 0;
+
+ /* Ensure a region being written, except the last one, ends on a
+ * character boundary.
+ */
+ unaligned_before = (-pos) % GLYPH_SZ;
+ if (unaligned_before < 0)
+ unaligned_before += GLYPH_SZ;
+
while (count) {
unsigned int this_round = count;
if (this_round > CON_BUF_SIZE)
this_round = CON_BUF_SIZE;
+ if (unaligned_before) {
+ this_round += unaligned_before;
+ if (this_round > CON_BUF_SIZE)
+ this_round -= GLYPH_SZ;
+ if (this_round > count)
+ this_round = count;
+ unaligned_before = 0;
+ }
+
/* Temporarily drop the console lock so that we can read
* in the write data from userspace safely.
*/
@@ -681,8 +761,13 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
written += this_round;
buf += this_round;
pos += this_round;
+ /* update_region needs ORG0 and ORG on character boundaries. */
+ org0 = (u16 *)((unsigned long)org0 & ~((unsigned long)GLYPH_SZ - 1));
+ org = (u16 *)(((unsigned long)org + GLYPH_SZ - 1) &
+ ~((unsigned long)GLYPH_SZ - 1));
if (org)
- update_region(vc, (unsigned long)(org0), org - org0);
+ update_region(vc, (unsigned long)(org0),
+ (org - org0) / GLYPH_HW);
}
*ppos += written;
ret = written;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 8f467b22b799..0c389a564357 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -566,7 +567,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
unsigned int row, unsigned int col, unsigned int nr)
{
u32 **uni_lines = vc->vc_uni_lines;
- int offset = row * vc->vc_size_row + col * 2;
+ int offset = row * vc->vc_size_row + col * GLYPH_SZ;
unsigned long pos;
if (WARN_ON_ONCE(!uni_lines))
@@ -580,7 +581,8 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
* scrollback is active.
*/
row = (pos - vc->vc_origin) / vc->vc_size_row;
- col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2;
+ col = ((pos - vc->vc_origin) % vc->vc_size_row) /
+ GLYPH_SZ;
memcpy(dest, &uni_lines[row][col], nr * sizeof(u32));
} else {
/*
@@ -620,7 +622,7 @@ static void con_scroll(struct vc_data *vc, unsigned int top,
dst = (u16 *)(vc->vc_origin + vc->vc_size_row * (top + nr));
if (dir == SM_UP) {
- clear = src + (rows - nr) * vc->vc_cols;
+ clear = src + (rows - nr) * vc->vc_cols * GLYPH_HW;
swap(src, dst);
}
scr_memmovew(dst, src, (rows - nr) * vc->vc_size_row);
@@ -632,7 +634,7 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
unsigned int xx, yy, offset;
u16 *p = (u16 *)start;
- offset = (start - vc->vc_origin) / 2;
+ offset = (start - vc->vc_origin) / GLYPH_SZ;
xx = offset % vc->vc_cols;
yy = offset / vc->vc_cols;
@@ -653,7 +657,9 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
count--;
}
if (p > q)
- vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+ vc->vc_sw->con_putcs(vc, q,
+ (p-q) / GLYPH_HW,
+ yy, startx);
if (!count)
break;
xx = 0;
@@ -736,7 +740,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, bool viewed)
WARN_CONSOLE_UNLOCKED();
- count /= 2;
+ count /= GLYPH_SZ;
p = screenpos(vc, offset, viewed);
if (vc->vc_sw->con_invert_region) {
vc->vc_sw->con_invert_region(vc, p, count);
@@ -818,8 +809,9 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
unsigned short *p = (unsigned short *) vc->vc_pos;
vc_uniscr_insert(vc, nr);
- scr_memmovew(p + nr, p, (vc->vc_cols - vc->state.x - nr) * 2);
- scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+ scr_memmovew(p + nr * GLYPH_HW,
+ p, (vc->vc_cols - vc->state.x - nr) * GLYPH_SZ);
+ scr_memset_worl(p, vc->vc_video_erase_char, nr * GLYPH_SZ);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
do_update_region(vc, (unsigned long) p,
@@ -831,9 +823,10 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
unsigned short *p = (unsigned short *) vc->vc_pos;
vc_uniscr_delete(vc, nr);
- scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
- scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
- nr * 2);
+ scr_memmovew(p, p + nr * GLYPH_HW,
+ (vc->vc_cols - vc->state.x - nr) * GLYPH_SZ);
+ scr_memset_worl(p + (vc->vc_cols - vc->state.x - nr) * GLYPH_HW,
+ vc->vc_video_erase_char, nr * GLYPH_SZ);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
do_update_region(vc, (unsigned long) p,
@@ -909,7 +902,7 @@ static void set_origin(struct vc_data *vc)
vc->vc_visible_origin = vc->vc_origin;
vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->state.y +
- 2 * vc->state.x;
+ GLYPH_SZ * vc->state.x;
}
static void save_screen(struct vc_data *vc)
@@ -1005,7 +999,9 @@ void redraw_screen(struct vc_data *vc, int is_switch)
}
if (update && vc->vc_mode != KD_GRAPHICS)
- do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+ do_update_region(vc, vc->vc_origin,
+ vc->vc_screenbuf_size /
+ GLYPH_SZ);
}
set_cursor(vc);
if (is_switch) {
@@ -1184,6 +1217,6 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
new_cols = (cols ? cols : vc->vc_cols);
new_rows = (lines ? lines : vc->vc_rows);
- new_row_size = new_cols << 1;
+ new_row_size = new_cols * GLYPH_SZ;
new_screen_size = new_row_size * new_rows;
if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) {
@@ -1233,13 +1266,9 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
return err;
}
- vc->vc_rows = new_rows;
- vc->vc_cols = new_cols;
- vc->vc_size_row = new_row_size;
- vc->vc_screenbuf_size = new_screen_size;
-
- rlth = min(old_row_size, new_row_size);
- rrem = new_row_size - rlth;
+ rlth = min(old_row_size / GLYPH_SZ,
+ new_row_size / GLYPH_SZ);
+ rrem = (new_row_size / GLYPH_SZ) - rlth;
old_origin = vc->vc_origin;
new_origin = (long) newscreen;
new_scr_end = new_origin + new_screen_size;
@@ -1264,24 +1293,37 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
end = old_origin + old_row_size * min(old_rows, new_rows);
vc_uniscr_copy_area(new_uniscr, new_cols, new_rows,
- vc->vc_uni_lines, rlth/2, first_copied_row,
+ vc->vc_uni_lines, rlth, first_copied_row,
min(old_rows, new_rows));
vc_uniscr_set(vc, new_uniscr);
+ vc->vc_cols = new_cols;
+ vc->vc_rows = new_rows;
+ vc->vc_size_row = new_row_size;
+ vc->vc_screenbuf_size = new_screen_size;
+
update_attr(vc);
while (old_origin < end) {
scr_memcpyw((unsigned short *) new_origin,
- (unsigned short *) old_origin, rlth);
+ (unsigned short *) old_origin,
+ rlth * GLYPH_SZ);
if (rrem)
- scr_memsetw((void *)(new_origin + rlth),
- vc->vc_video_erase_char, rrem);
+ scr_memset_worl((void *) (new_origin +
+ rlth * GLYPH_SZ),
+ new_vc_video_erase_char,
+ rrem * GLYPH_SZ);
old_origin += old_row_size;
new_origin += new_row_size;
}
if (new_scr_end > new_origin)
- scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
- new_scr_end - new_origin);
+ scr_memset_worl((void *)new_origin,
+ new_vc_video_erase_char,
+ new_scr_end - new_origin);
+ vc->vc_char_mask = new_vc_char_mask;
+ vc->vc_attr_mask = new_vc_attr_mask;
+ vc->vc_attr_shift_pos = new_vc_attr_shift_pos;
+ vc->vc_video_erase_char = new_vc_video_erase_char;
oldscreen = vc->vc_screenbuf;
vc->vc_screenbuf = newscreen;
vc->vc_screenbuf_size = new_screen_size;
@@ -1452,7 +1494,7 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y)
else
vc->state.y = new_y;
vc->vc_pos = vc->vc_origin + vc->state.y * vc->vc_size_row +
- (vc->state.x << 1);
+ (vc->state.x * GLYPH_SZ);
vc->vc_need_wrap = 0;
}
@@ -1505,7 +1547,7 @@ static void ri(struct vc_data *vc)
static inline void cr(struct vc_data *vc)
{
- vc->vc_pos -= vc->state.x << 1;
+ vc->vc_pos -= vc->state.x * GLYPH_SZ;
vc->vc_need_wrap = vc->state.x = 0;
notify_write(vc, '\r');
}
@@ -1513,7 +1555,7 @@ static inline void cr(struct vc_data *vc)
static inline void bs(struct vc_data *vc)
{
if (vc->state.x) {
- vc->vc_pos -= 2;
+ vc->vc_pos -= GLYPH_SZ;
vc->state.x--;
vc->vc_need_wrap = 0;
notify_write(vc, '\b');
@@ -1543,13 +1585,13 @@ static void csi_J(struct vc_data *vc, enum CSI_J vpar)
vc->vc_cols - vc->state.x);
vc_uniscr_clear_lines(vc, vc->state.y + 1,
vc->vc_rows - vc->state.y - 1);
- count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+ count = (vc->vc_scr_end - vc->vc_pos) / GLYPH_SZ;
start = (unsigned short *)vc->vc_pos;
break;
case CSI_J_START_TO_CURSOR:
vc_uniscr_clear_line(vc, 0, vc->state.x + 1);
vc_uniscr_clear_lines(vc, 0, vc->state.y);
- count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+ count = ((vc->vc_pos - vc->vc_origin) / GLYPH_SZ) + 1;
start = (unsigned short *)vc->vc_origin;
break;
case CSI_J_FULL:
@@ -1563,7 +1605,8 @@ static void csi_J(struct vc_data *vc, enum CSI_J vpar)
default:
return;
}
- scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+ scr_memset_worl(start, vc->vc_video_erase_char,
+ GLYPH_SZ * count);
if (con_should_update(vc))
do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0;
@@ -1598,10 +1641,13 @@ static void csi_K(struct vc_data *vc)
return;
}
vc_uniscr_clear_line(vc, vc->state.x + offset, count);
- scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
+ scr_memset_worl(start + offset * (int)GLYPH_HW,
+ vc->vc_video_erase_char, GLYPH_SZ * count);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
- do_update_region(vc, (unsigned long)(start + offset), count);
+ do_update_region(vc, (unsigned long)(start + offset *
+ (int)GLYPH_HW),
+ count);
}
/* erase the following count positions */
@@ -1610,7 +1656,8 @@ static void csi_X(struct vc_data *vc)
unsigned int count = clamp(vc->vc_par[0], 1, vc->vc_cols - vc->state.x);
vc_uniscr_clear_line(vc, vc->state.x, count);
- scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
+ scr_memset_worl((unsigned short *)vc->vc_pos, vc->vc_video_erase_char,
+ GLYPH_SZ * count);
if (con_should_update(vc))
vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, count);
vc->vc_need_wrap = 0;
@@ -1912,7 +1959,7 @@ static int get_bracketed_paste(struct tty_struct *tty)
/* console_lock is held */
static void enter_alt_screen(struct vc_data *vc)
{
- unsigned int size = vc->vc_rows * vc->vc_cols * 2;
+ unsigned int size = vc->vc_rows * vc->vc_cols * GLYPH_SZ;
if (vc->vc_saved_screen != NULL)
return; /* Already inside an alt-screen */
@@ -1938,9 +1985,11 @@ static void leave_alt_screen(struct vc_data *vc)
if (vc->vc_saved_screen == NULL)
return; /* Not inside an alt-screen */
for (unsigned int r = 0; r < rows; r++) {
- src = vc->vc_saved_screen + r * vc->vc_saved_cols;
- dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
- memcpy(dest, src, 2 * cols);
+ src = vc->vc_saved_screen +
+ GLYPH_HW * r * vc->vc_saved_cols;
+ dest = ((u16 *)vc->vc_origin) +
+ GLYPH_HW * r * vc->vc_cols;
+ memcpy(dest, src, GLYPH_SZ * cols);
}
/*
* If the console was resized while in the alternate screen,
@@ -1965,7 +2014,8 @@ static void leave_alt_screen(struct vc_data *vc)
restore_cur(vc);
/* Update the entire screen */
if (con_should_update(vc))
- do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+ do_update_region(vc, vc->vc_origin,
+ vc->vc_screenbuf_size / GLYPH_SZ);
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
}
@@ -2385,7 +2437,7 @@ static bool handle_ascii(struct tty_struct *tty, struct vc_data *vc, u8 c)
bs(vc);
return true;
case ASCII_HTAB:
- vc->vc_pos -= (vc->state.x << 1);
+ vc->vc_pos -= (vc->state.x * GLYPH_SZ);
vc->state.x = find_next_bit(vc->vc_tab_stop,
min(vc->vc_cols - 1, VC_TABSTOPS_COUNT),
@@ -2393,7 +2445,7 @@ static bool handle_ascii(struct tty_struct *tty, struct vc_data *vc, u8 c)
if (vc->state.x >= VC_TABSTOPS_COUNT)
vc->state.x = vc->vc_cols - 1;
- vc->vc_pos += (vc->state.x << 1);
+ vc->vc_pos += (vc->state.x * GLYPH_SZ);
notify_write(vc, '\t');
return true;
case ASCII_LINEFEED:
@@ -2895,8 +2949,9 @@ static void con_flush(struct vc_data *vc, struct vc_draw_region *draw)
return;
vc->vc_sw->con_putcs(vc, (u16 *)draw->from,
- (u16 *)draw->to - (u16 *)draw->from, vc->state.y,
- draw->x);
+ (int)((u16 *)draw->to - (u16 *)draw->from) /
+ GLYPH_HW,
+ vc->state.y, draw->x);
draw->x = -1;
}
@@ -3081,7 +3138,7 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
static void vc_con_rewind(struct vc_data *vc)
{
if (vc->state.x && !vc->vc_need_wrap) {
- vc->vc_pos -= 2;
+ vc->vc_pos -= GLYPH_SZ;
vc->state.x--;
}
vc->vc_need_wrap = 0;
@@ -3111,7 +3168,7 @@ static int vc_process_ucs(struct vc_data *vc, int *c, int *tc)
/* From here curr_c is known to be zero-width. */
- if (ucs_get_width(vc_uniscr_getc(vc, -2)) == 2) {
+ if (ucs_get_width(vc_uniscr_getc(vc, -GLYPH_SZ)) == 2) {
/*
* Let's merge this zero-width code point with the preceding
* double-width code point by replacing the existing
@@ -3243,10 +3298,10 @@ static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
}
if (vc->state.x == vc->vc_cols - 1) {
vc->vc_need_wrap = vc->vc_decawm;
- draw->to = vc->vc_pos + 2;
+ draw->to = vc->vc_pos + GLYPH_SZ;
} else {
vc->state.x++;
- draw->to = (vc->vc_pos += 2);
+ draw->to = (vc->vc_pos += GLYPH_SZ);
}
if (!--width)
@@ -3508,7 +3564,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
if (vc->state.x == vc->vc_cols - 1) {
vc->vc_need_wrap = 1;
} else {
- vc->vc_pos += 2;
+ vc->vc_pos += GLYPH_SZ;
vc->state.x++;
}
}
@@ -5065,14 +5125,15 @@ u32 screen_glyph_unicode(const struct vc_data *vc, int n)
if (uni_lines)
return uni_lines[n / vc->vc_cols][n % vc->vc_cols];
- return inverse_translate(vc, screen_glyph(vc, n * 2), true);
+ return inverse_translate(vc, screen_glyph(vc, n * GLYPH_SZ),
+ true);
}
EXPORT_SYMBOL_GPL(screen_glyph_unicode);
-/* used by vcs - note the word offset */
+/* used by vcs - note the (screen)char sized offset */
unsigned short *screen_pos(const struct vc_data *vc, int w_offset, bool viewed)
{
- return screenpos(vc, 2 * w_offset, viewed);
+ return screenpos(vc, GLYPH_SZ * w_offset, viewed);
}
EXPORT_SYMBOL_GPL(screen_pos);
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 65681dcc5930..84e073162311 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -214,7 +213,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
image.dx += cnt * vc->vc_font.width;
count -= cnt;
- s += cnt;
+ s += GLYPH_HW * cnt;
}
/* buf is always NULL except when in monochrome mode, so in this case
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 9f5c4c101581..18fbf7cf11dd 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -668,22 +668,28 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
break;
if (r != q && new_rows >= rows + logo_lines) {
- save = kmalloc(array3_size(logo_lines, new_cols, 2),
+ save = kmalloc(array3_size(logo_lines, new_cols, GLYPH_SZ),
GFP_KERNEL);
if (save) {
int i = min(cols, new_cols);
- scr_memsetw(save, erase, array3_size(logo_lines, new_cols, 2));
- r = q - step;
- for (cnt = 0; cnt < logo_lines; cnt++, r += i)
- scr_memcpyw(save + cnt * new_cols, r, 2 * i);
+ scr_memset_worl(save, erase, array3_size(logo_lines,
+ new_cols,
+ GLYPH_SZ));
+ r = q - step * GLYPH_HW;
+ for (cnt = 0; cnt < logo_lines;
+ cnt++, r += i * GLYPH_HW)
+ scr_memcpyw(save +
+ cnt * new_cols * GLYPH_HW,
+ r, GLYPH_SZ * i);
r = q;
}
}
if (r == q) {
/* We can scroll screen down */
- r = q - step - cols;
+ r = q - (step + cols) * GLYPH_HW;
for (cnt = rows - logo_lines; cnt > 0; cnt--) {
- scr_memcpyw(r + step, r, vc->vc_size_row);
- r -= cols;
+ scr_memcpyw(r + step * GLYPH_HW,
+ r, vc->vc_size_row);
+ r -= cols * GLYPH_HW;
}
if (!save) {
int lines;
@@ -708,7 +714,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
q = (unsigned short *) (vc->vc_origin +
vc->vc_size_row *
rows);
- scr_memcpyw(q, save, array3_size(logo_lines, new_cols, 2));
+ scr_memcpyw(q, save, array3_size(logo_lines, new_cols, GLYPH_SZ));
vc->state.y += logo_lines;
vc->vc_pos += logo_lines * vc->vc_size_row;
kfree(save);
@@ -1714,7 +1734,7 @@ static void fbcon_redraw(struct vc_data *vc, int line, int count, int offset)
{
unsigned short *d = (unsigned short *)
(vc->vc_origin + vc->vc_size_row * line);
- unsigned short *s = d + offset;
+ unsigned short *s = d + ((long) offset) * GLYPH_HW;
while (count--) {
unsigned short *start = s;
@@ -2260,7 +2296,7 @@ static bool fbcon_switch(struct vc_data *vc)
update_region(vc,
vc->vc_origin + vc->vc_size_row * vc->vc_top,
vc->vc_size_row * (vc->vc_bottom -
- vc->vc_top) / 2);
+ vc->vc_top) / GLYPH_SZ);
return false;
}
return true;
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index fe915afdece5..5afce52057ca 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -29,6 +30,14 @@ enum vc_intensity {
VCI_MASK = 0x3,
};
+#ifdef CONFIG_FB_GLYPH_21BIT
+#define GLYPH_SZ 4 /* Size of glyph in bytes */
+#define GLYPH_HW 2 /* Size of glyph in u16s ("Half Words") */
+#else
+#define GLYPH_SZ 2
+#define GLYPH_HW 1
+#endif
+
/**
* struct vc_state -- state of a VC
* @x: cursor's x-position
--
Alan Mackenzie (Nuremberg, Germany)
next prev parent reply other threads:[~2026-08-27 18:45 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 18:38 vt: Enlarge the framebuffer glyph size from 16 to 32 bits Alan Mackenzie
2026-08-27 18:42 ` [Patch 1/9]: Make consolemap.c handle Unicode planes outside BMP Alan Mackenzie
2026-08-28 4:57 ` Jiri Slaby
2026-08-27 18:45 ` Alan Mackenzie [this message]
2026-08-27 18:47 ` [Patch 3/9]: Replace scr_readw/writew by scr_readg/writeg, etc Alan Mackenzie
2026-08-27 18:48 ` [Patch 4/9]: Amend internal manipulation of glyph structure Alan Mackenzie
2026-08-27 18:50 ` [Patch 5/9]: vt: Amend three Kconfig files Alan Mackenzie
2026-08-27 18:52 ` [Patch 6/9]: vt: Use u32 and typedef u1632 to handle whole glyphs Alan Mackenzie
2026-08-27 18:54 ` [Patch 7/9]: vt: Handle up to 2^21 glyphs, rather than 256/512 Alan Mackenzie
2026-08-27 18:56 ` [Patch 8/9]: vt: Enhancements to the VT ioctl interface Alan Mackenzie
2026-08-27 18:58 ` [Patch 9/9]: vt: Misc changes, e.g. to #include directives Alan Mackenzie
2026-08-28 6:12 ` vt: Enlarge the framebuffer glyph size from 16 to 32 bits Thomas Zimmermann
2026-08-28 14:36 ` Alan Mackenzie
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=apCFsX_JXJ9m3vpr@MAC.fritz.box \
--to=acm@muc.de \
--cc=deller@gmx.de \
--cc=dri-devel@lists.freedesktop.org \
--cc=gregkh@linuxfoundation.org \
--cc=jirislaby@kernel.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tzimmermann@suse.de \
/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
all inboxes | Powered by JetHome®