aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2023-01-16 23:46:28 +0100
committerAlexey Gladkov <gladkov.alexey@gmail.com>2023-04-24 14:00:40 +0200
commit287a3baeb8fc2fc6fd68b3accff8f9651d725d16 (patch)
treea57b6ec54a4dce1510b352600d0b69380594921a
parentc3c7b46883127ef6ccfbec9610c7c6f48d443683 (diff)
downloadkbd-287a3baeb8fc2fc6fd68b3accff8f9651d725d16.tar.gz
font: Leverage KD_FONT_OP_GET/SET_TALL font operations
The new KD_FONT_OP_GET/SET_TALL font operations allow to load fonts taller than 32 pixels by dropping the VGA-specific vertical pitch limitation. The new maximum font size has thus been raised to 64x128. We however continue using the older font operations for smaller fonts, to continue supporting older kernels. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
-rw-r--r--src/compat/linux-kd.h5
-rw-r--r--src/libkfont/kdfontop.c58
-rw-r--r--src/libkfont/kfont.h8
-rw-r--r--src/libkfont/setfont.c45
-rw-r--r--src/showconsolefont.c2
-rw-r--r--tests/libtswrap/ioctl.c6
6 files changed, 94 insertions, 30 deletions
diff --git a/src/compat/linux-kd.h b/src/compat/linux-kd.h
index d086b65a..baa0761d 100644
--- a/src/compat/linux-kd.h
+++ b/src/compat/linux-kd.h
@@ -90,7 +90,8 @@ struct console_font_op {
unsigned int flags; /* KD_FONT_FLAG_* */
unsigned int width, height;
unsigned int charcount;
- unsigned char *data; /* font data with height fixed to 32 */
+ unsigned char *data; /* font data with vpitch fixed to 32 for
+ * KD_FONT_OP_SET/GET */
};
#define KD_FONT_OP_SET 0 /* Set font */
@@ -98,6 +99,8 @@ struct console_font_op {
#define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, \
data points to name / NULL */
#define KD_FONT_OP_COPY 3 /* Copy from another console */
+#define KD_FONT_OP_SET_TALL 4 /* Set font with arbitrary vpitch */
+#define KD_FONT_OP_GET_TALL 5 /* Get font with arbitrary vpitch */
#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */
#define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */
diff --git a/src/libkfont/kdfontop.c b/src/libkfont/kdfontop.c
index 3b340da5..209f6fce 100644
--- a/src/libkfont/kdfontop.c
+++ b/src/libkfont/kdfontop.c
@@ -51,19 +51,33 @@ get_font_kdfontop(struct kfont_context *ctx, int consolefd,
unsigned char *buf,
unsigned int *count,
unsigned int *width,
- unsigned int *height)
+ unsigned int *height,
+ unsigned int *vpitch)
{
struct console_font_op cfo;
+#ifdef KD_FONT_OP_GET_TALL
+ cfo.op = KD_FONT_OP_GET_TALL;
+#else
cfo.op = KD_FONT_OP_GET;
+#endif
cfo.flags = 0;
- cfo.width = cfo.height = 32;
+ cfo.width = 64;
+ cfo.height = 128;
cfo.charcount = *count;
cfo.data = buf;
+retry:
errno = 0;
if (ioctl(consolefd, KDFONTOP, &cfo)) {
+#ifdef KD_FONT_OP_GET_TALL
+ if (errno == ENOSYS && cfo.op == KD_FONT_OP_GET_TALL) {
+ /* Kernel before 6.2. */
+ cfo.op = KD_FONT_OP_GET;
+ goto retry;
+ }
+#endif
if (errno != ENOSYS && errno != EINVAL) {
KFONT_ERR(ctx, "ioctl(KDFONTOP): %m");
return -1;
@@ -76,6 +90,14 @@ get_font_kdfontop(struct kfont_context *ctx, int consolefd,
*height = cfo.height;
if (width)
*width = cfo.width;
+ if (vpitch) {
+#ifdef KD_FONT_OP_GET_TALL
+ if (cfo.op == KD_FONT_OP_GET_TALL)
+ *vpitch = cfo.height;
+ else
+#endif
+ *vpitch = 32;
+ }
return 0;
}
@@ -88,16 +110,17 @@ int
kfont_get_font(struct kfont_context *ctx, int fd, unsigned char *buf,
unsigned int *count,
unsigned int *width,
- unsigned int *height)
+ unsigned int *height,
+ unsigned int *vpitch)
{
- return get_font_kdfontop(ctx, fd, buf, count, width, height);
+ return get_font_kdfontop(ctx, fd, buf, count, width, height, vpitch);
}
int unsigned
kfont_get_fontsize(struct kfont_context *ctx, int fd)
{
unsigned int count = 0;
- if (!kfont_get_font(ctx, fd, NULL, &count, NULL, NULL))
+ if (!kfont_get_font(ctx, fd, NULL, &count, NULL, NULL, NULL))
return count;
return 256;
}
@@ -106,11 +129,20 @@ static int
put_font_kdfontop(struct kfont_context *ctx, int consolefd, unsigned char *buf,
unsigned int count,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ unsigned int vpitch)
{
struct console_font_op cfo;
- cfo.op = KD_FONT_OP_SET;
+ if (vpitch == 32 && width <= 32)
+ cfo.op = KD_FONT_OP_SET;
+ else {
+#ifdef KD_FONT_OP_SET_TALL
+ cfo.op = KD_FONT_OP_SET_TALL;
+#else
+ return 0;
+#endif
+ }
cfo.flags = 0;
cfo.width = width;
cfo.height = height;
@@ -122,8 +154,14 @@ put_font_kdfontop(struct kfont_context *ctx, int consolefd, unsigned char *buf,
if (!ioctl(consolefd, KDFONTOP, &cfo))
return 0;
- if (errno == ENOSYS)
+ if (errno == ENOSYS) {
+#ifdef KD_FONT_OP_SET_TALL
+ if (cfo.op == KD_FONT_OP_SET_TALL)
+ /* Let user know that we can't load such font with such kernel version */
+ return 0;
+#endif
return 1;
+ }
int ret = -1;
@@ -154,7 +192,7 @@ put_font_kdfontop(struct kfont_context *ctx, int consolefd, unsigned char *buf,
int
kfont_put_font(struct kfont_context *ctx, int fd, unsigned char *buf, unsigned int count,
- unsigned int width, unsigned int height)
+ unsigned int width, unsigned int height, unsigned int vpitch)
{
if (!width)
width = 8;
@@ -162,5 +200,5 @@ kfont_put_font(struct kfont_context *ctx, int fd, unsigned char *buf, unsigned i
if (!height)
height = font_charheight(buf, count, width);
- return put_font_kdfontop(ctx, fd, buf, count, width, height);
+ return put_font_kdfontop(ctx, fd, buf, count, width, height, vpitch);
}
diff --git a/src/libkfont/kfont.h b/src/libkfont/kfont.h
index 2c47aa16..4c2b0221 100644
--- a/src/libkfont/kfont.h
+++ b/src/libkfont/kfont.h
@@ -171,7 +171,8 @@ int kfont_load_unicodemap(struct kfont_context *ctx, int consolefd,
* Sets number of glyphs in COUNT, glyph size in WIDTH and HEIGHT.
*/
int kfont_get_font(struct kfont_context *ctx, int consolefd, unsigned char *buf,
- unsigned int *count, unsigned int *width, unsigned int *height)
+ unsigned int *count, unsigned int *width, unsigned int *height,
+ unsigned int *vpitch)
__attribute__((nonnull(1)));
/*
@@ -180,7 +181,8 @@ int kfont_get_font(struct kfont_context *ctx, int consolefd, unsigned char *buf,
* Return 0 on success, -1 on failure.
*/
int kfont_put_font(struct kfont_context *ctx, int consolefd, unsigned char *buf,
- unsigned int count, unsigned int width, unsigned int height)
+ unsigned int count, unsigned int width, unsigned int height,
+ unsigned int vpitch)
__attribute__((nonnull(1)));
/*
@@ -239,7 +241,7 @@ void kfont_disactivatemap(int fd);
#include <stdio.h>
/* Maximum font size that we try to handle */
-#define MAXFONTSIZE 65536
+#define MAXFONTSIZE (512*64*128)
/**
* readpsffont reads a PSF font.
diff --git a/src/libkfont/setfont.c b/src/libkfont/setfont.c
index 9a0bb72c..ec7ede17 100644
--- a/src/libkfont/setfont.c
+++ b/src/libkfont/setfont.c
@@ -45,8 +45,9 @@ findpartialfont(struct kfont_context *ctx, const char *fnam, struct kbdfile *fp)
static int erase_mode = 1;
static int
-do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
- unsigned int width, unsigned int height, unsigned int hwunit,
+try_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
+ unsigned int width, unsigned int height, unsigned int vpitch,
+ unsigned int hwunit,
unsigned int fontsize, const char *filename)
{
unsigned char *buf = NULL;
@@ -54,13 +55,13 @@ do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
int bad_video_erase_char = 0;
int ret;
- if (height < 1 || height > 32) {
- KFONT_ERR(ctx, _("Bad character height %d"), height);
+ if (height < 1 || height > 128) {
+ KFONT_ERR(ctx, _("Bad character height %d (limit is 128)"), height);
return -EX_DATAERR;
}
- if (width < 1 || width > 32) {
- KFONT_ERR(ctx, _("Bad character width %d"), width);
+ if (width < 1 || width > 64) {
+ KFONT_ERR(ctx, _("Bad character width %d (limit is 64)"), width);
return -EX_DATAERR;
}
@@ -68,8 +69,8 @@ do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
hwunit = height;
if ((ctx->options & (1 << kfont_double_size)) &&
- (height > 16 || width > 16)) {
- KFONT_ERR(ctx, _("Cannot double %dx%d font (limit is 16x16)"), width, height);
+ (height > 64 || width > 32)) {
+ KFONT_ERR(ctx, _("Cannot double %dx%d font (limit is 32x64)"), width, height);
kfont_unset_option(ctx, kfont_double_size);
}
@@ -78,7 +79,7 @@ do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
unsigned int kbytewidth = (2 * width + 7) / 8;
unsigned int charsize = height * bytewidth;
- kcharsize = 32 * kbytewidth;
+ kcharsize = vpitch * kbytewidth;
buflen = kcharsize * ((fontsize < 128) ? 128 : fontsize);
buf = calloc(1, buflen);
@@ -112,7 +113,7 @@ do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
unsigned int bytewidth = (width + 7) / 8;
unsigned int charsize = height * bytewidth;
- kcharsize = 32 * bytewidth;
+ kcharsize = vpitch * bytewidth;
buflen = kcharsize * ((fontsize < 128) ? 128 : fontsize);
buf = calloc(1, buflen);
@@ -169,7 +170,7 @@ do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
KFONT_INFO(ctx, _("Loading %d-char %dx%d (%d) font"),
fontsize, width, height, hwunit);
- if (kfont_put_font(ctx, fd, buf, fontsize, width, hwunit) < 0) {
+ if (kfont_put_font(ctx, fd, buf, fontsize, width, hwunit, vpitch) < 1) {
ret = -EX_OSERR;
goto err;
}
@@ -181,6 +182,20 @@ err:
}
static int
+do_loadfont(struct kfont_context *ctx, int fd, const unsigned char *inbuf,
+ unsigned int width, unsigned int height, unsigned int hwunit,
+ unsigned int fontsize, const char *filename)
+{
+ int ret;
+
+ if (height <= 32 && width <= 32)
+ /* This can work with pre-6.2 kernels and its size and vpitch limitations */
+ return try_loadfont(ctx, fd, inbuf, width, height, 32, hwunit, fontsize, filename);
+ else
+ return try_loadfont(ctx, fd, inbuf, width, height, height, hwunit, fontsize, filename);
+}
+
+static int
do_loadtable(struct kfont_context *ctx, int fd, struct unicode_list *uclistheads,
unsigned int fontsize)
{
@@ -585,19 +600,19 @@ save_font(struct kfont_context *ctx, int consolefd, const char *filename,
/* this is the max font size the kernel is willing to handle */
unsigned char buf[MAXFONTSIZE];
- unsigned int i, ct, width, height, bytewidth, charsize, kcharsize;
+ unsigned int i, ct, width, height, bytewidth, charsize, kcharsize, vpitch;
int ret;
- ct = sizeof(buf) / (32 * 32 / 8); /* max size 32x32, 8 bits/byte */
+ ct = sizeof(buf) / (64 * 128 / 8); /* max size 64x128, 8 bits/byte */
- if (kfont_get_font(ctx, consolefd, buf, &ct, &width, &height) < 0)
+ if (kfont_get_font(ctx, consolefd, buf, &ct, &width, &height, &vpitch) < 0)
return -EX_OSERR;
/* save as efficiently as possible */
bytewidth = (width + 7) / 8;
height = font_charheight(buf, ct, width);
charsize = height * bytewidth;
- kcharsize = 32 * bytewidth;
+ kcharsize = vpitch * bytewidth;
/* Do we need a psf header? */
/* Yes if ct==512 - otherwise we cannot distinguish
diff --git a/src/showconsolefont.c b/src/showconsolefont.c
index ac0afb32..b16072f2 100644
--- a/src/showconsolefont.c
+++ b/src/showconsolefont.c
@@ -205,7 +205,7 @@ int main(int argc, char **argv)
if (info) {
nr = rows = cols = 0;
- ret = kfont_get_font(kfont, fd, NULL, &nr, &rows, &cols);
+ ret = kfont_get_font(kfont, fd, NULL, &nr, &rows, &cols, NULL);
if (ret != 0)
leave(kfont, EXIT_FAILURE);
diff --git a/tests/libtswrap/ioctl.c b/tests/libtswrap/ioctl.c
index ada9189b..64b22343 100644
--- a/tests/libtswrap/ioctl.c
+++ b/tests/libtswrap/ioctl.c
@@ -93,6 +93,12 @@ static struct translate_names kd_font_op[] = {
{ KD_FONT_OP_GET, "KD_FONT_OP_GET" },
{ KD_FONT_OP_SET_DEFAULT, "KD_FONT_OP_SET_DEFAULT" },
{ KD_FONT_OP_COPY, "KD_FONT_OP_COPY" },
+#ifdef KD_FONT_OP_SET_TALL
+ { KD_FONT_OP_SET_TALL, "KD_FONT_OP_SET_TALL" },
+#endif
+#ifdef KD_FONT_OP_GET_TALL
+ { KD_FONT_OP_GET_TALL, "KD_FONT_OP_GET_TALL" },
+#endif
{ 0, NULL }
};