1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
// SPDX-License-Identifier: LGPL-2.0-or-later
/*
* Copyright (C) 2007-2020 Alexey Gladkov <gladkov.alexey@gmail.com>
*
* Originally written by Andries Brouwer
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include "libcommon.h"
#include "kfontP.h"
/*
* Linux pre-0.96 defined GIO_SCRNMAP, PIO_SCRNMAP:
typedef char scrnmap_t;
#define E_TABSZ 256
#define GIO_SCRNMAP 0x4B40
#define PIO_SCRNMAP 0x4B41
* and Linux 0.99.14y first implemented them.
* Usage:
scrnmap_t map[E_TABSZ];
ioctl(fd,GIO_SCRNMAP,map);
ioctl(fd,PIO_SCRNMAP,map);
* to read or write the kernel translation table that is
* applied to user application output before displaying.
*
* Before 1.3.1, the character set was completely undetermined,
* and if the font was in an order different from the character
* set in use, the user screen map was used to map application
* codes to font indices. (To be more precise: there were four
* translation tables, and this ioctl would get/set the fourth
* table, while the other three tables are built-in and constant.)
*/
int getscrnmap(struct kfont_context *ctx, int fd, unsigned char *map)
{
if (ioctl(fd, GIO_SCRNMAP, map)) {
KFONT_ERR(ctx, "ioctl(GIO_SCRNMAP): %m");
return -1;
}
return 0;
}
int loadscrnmap(struct kfont_context *ctx, int fd, unsigned char *map)
{
if (ioctl(fd, PIO_SCRNMAP, map)) {
KFONT_ERR(ctx, "ioctl(PIO_SCRNMAP): %m");
return -1;
}
return 0;
}
/*
* Linux 1.3.1 introduces GIO_UNISCRNMAP, PIO_UNISCRNMAP:
#define GIO_UNISCRNMAP 0x4B69
#define PIO_UNISCRNMAP 0x4B6A
* Usage:
unsigned short umap[E_TABSZ];
ioctl(fd,GIO_UNISCRNMAP,umap);
ioctl(fd,PIO_UNISCRNMAP,umap);
* to read or write the kernel translation table that is
* applied to user application output before displaying.
* (When the console is not in utf8 mode.)
*
* The idea is that the umap values are 16-bit unicode (ucs2)
* values, and that the fonts will have an index giving the
* unicode value for each glyph, so that the kernel can match up
* application codes to font positions.
#define UNI_DIRECT_BASE 0xF000
#define UNI_DIRECT_MASK 0x01FF
* For compatibility, and for fonts without table, the unicode
* values 0xF000+n, 0 <= n <= 0x01FF, acts as direct font indices.
* In the new scheme, the old PIO_SCRNMAP fills the kernel umap
* table with such direct-to-font values.
*/
int
kfont_get_uniscrnmap(struct kfont_context *ctx, int fd, unsigned short *map)
{
if (ioctl(fd, GIO_UNISCRNMAP, map)) {
KFONT_ERR(ctx, "ioctl(GIO_UNISCRNMAP): %m");
return -1;
}
return 0;
}
int
kfont_put_uniscrnmap(struct kfont_context *ctx, int fd, unsigned short *map)
{
unsigned short inbuf[E_TABSZ];
/*
* PIO_UNISCRNMAP uses an array of size E_TABSZ as an argument.
*/
memcpy(inbuf, map, sizeof(inbuf));
if (ioctl(fd, PIO_UNISCRNMAP, inbuf)) {
KFONT_ERR(ctx, "ioctl(PIO_UNISCRNMAP): %m");
return -1;
}
return 0;
}
/*
* Linux 1.1.63 introduces GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR:
#define GIO_UNIMAP 0x4B66
#define PIO_UNIMAP 0x4B67
#define PIO_UNIMAPCLR 0x4B68
* And Linux 1.1.92 implements them.
* Usage:
struct unimapinit {
unsigned short advised_hashsize;
unsigned short advised_hashstep;
unsigned short advised_hashlevel;
} ui;
ioctl(fd, PIO_UNIMAPCLR, &ui);
* to clear the unimap table and advise about the kind of
* hash setup appropriate to what one is going to load
* (with 0 for "don't care").
struct unipair {
unsigned short unicode;
unsigned short fontpos;
};
struct unimapdesc {
unsigned short entry_ct;
struct unipair *entries;
} ud;
ioctl(fd, PIO_UNIMAP, &ud);
ioctl(fd, GIO_UNIMAP, &ud);
* to add the indicated pairs to the kernel unimap table
* or to read the kernel unimap table, where in the latter case
* ud.entry_ct indicated the room available.
*
* In Linux 1.3.28 the hash table was replaced by a 3-level
* paged table, so the contents of a struct unimapinit are
* no longer meaningful.
*
* Linux 2.6.1 makes GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR per-vt
* so that fd no longer is random.
*/
int
kfont_get_unicodemap(struct kfont_context *ctx, int fd, struct unimapdesc *ud0)
{
struct unimapdesc ud;
unsigned int ct;
ud.entry_ct = 0;
ud.entries = 0;
if (ioctl(fd, GIO_UNIMAP, &ud)) {
if (errno != ENOMEM || ud.entry_ct == 0) {
KFONT_ERR(ctx, "ioctl(GIO_UNIMAP): %m");
return -1;
}
ct = ud.entry_ct;
ud.entries = malloc(ct * sizeof(struct unipair));
if (ud.entries == NULL) {
KFONT_ERR(ctx, "malloc: %m");
return -1;
}
if (ioctl(fd, GIO_UNIMAP, &ud)) {
KFONT_ERR(ctx, "ioctl(GIO_UNIMAP): %m");
return -1;
}
if (ct != ud.entry_ct)
KFONT_ERR(ctx, _("strange... ct changed from %d to %d"), ct, ud.entry_ct);
/* someone could change the unimap between our
first and second ioctl, so the above errors
are not impossible */
}
*ud0 = ud;
return 0;
}
int
kfont_put_unicodemap(struct kfont_context *ctx, int fd, struct unimapinit *ui, struct unimapdesc *ud)
{
struct unimapinit advice;
if (ui)
advice = *ui;
else {
advice.advised_hashsize = 0;
advice.advised_hashstep = 0;
advice.advised_hashlevel = 0;
}
again:
if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
#ifdef ENOIOCTLCMD
if (errno == ENOIOCTLCMD) {
KFONT_ERR(ctx,
_("It seems this kernel is older than 1.1.92\n"
"No Unicode mapping table loaded."));
} else
#endif
KFONT_ERR(ctx, "ioctl(PIO_UNIMAPCLR): %m");
return -1;
}
if (ud == NULL)
return 0;
if (ioctl(fd, PIO_UNIMAP, ud)) {
if (errno == ENOMEM && advice.advised_hashlevel < 100) {
advice.advised_hashlevel++;
goto again;
}
KFONT_ERR(ctx, "ioctl(PIO_UNIMAP): %m");
return -1;
}
return 0;
}
|