1 /* vi: set sw=4 ts=4: */
3 * loadfont.c - Eugene Crosser & Andries Brouwer
7 * Loads the console font, and possibly the corresponding screen map(s).
8 * (Adapted for busybox by Matej Vela.)
10 * Licensed under GPLv2, see file LICENSE in this tarball for details.
16 #define KDFONTOP 0x4B72
17 struct console_font_op {
18 unsigned op; /* KD_FONT_OP_* */
19 unsigned flags; /* KD_FONT_FLAG_* */
20 unsigned width, height;
22 unsigned char *data; /* font data with height fixed to 32 */
25 #define KD_FONT_OP_SET 0 /* Set font */
26 #define KD_FONT_OP_GET 1 /* Get font */
27 #define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default,
28 data points to name / NULL */
29 #define KD_FONT_OP_COPY 3 /* Copy from another console */
31 #define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */
32 #define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */
33 /* (Used internally for PIO_FONT support) */
42 PSF_MODEHASTAB = 0x02,
44 PSF_SEPARATOR = 0xffff
48 unsigned char magic1, magic2; /* Magic number */
49 unsigned char mode; /* PSF font mode */
50 unsigned char charsize; /* Character size */
53 #define PSF_MAGIC_OK(x) ((x)->magic1 == PSF_MAGIC1 && (x)->magic2 == PSF_MAGIC2)
55 static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize)
60 if (unit < 1 || unit > 32)
61 bb_error_msg_and_die("bad character size %d", unit);
63 buf = xzalloc(16 * 1024);
64 for (i = 0; i < fontsize; i++)
65 memcpy(buf + (32 * i), inbuf + (unit * i), unit);
68 struct console_font_op cfo;
70 cfo.op = KD_FONT_OP_SET;
74 cfo.charcount = fontsize;
75 cfo.data = (void*)buf;
77 if (!ioctl_or_perror(fd, KDFONTOP, &cfo, "KDFONTOP ioctl failed (will try PIO_FONTX)"))
78 goto ret; /* success */
80 xioctl(fd, KDFONTOP, &cfo);
85 /* These ones do not honour -C tty (they set font on current tty regardless)
86 * On x86, this distinction is visible on framebuffer consoles
87 * (regular character consoles may have only one shared font anyway)
89 #if defined(PIO_FONTX) && !defined(__sparc__)
91 struct consolefontdesc cfd;
93 cfd.charcount = fontsize;
94 cfd.charheight = unit;
97 if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)"))
98 goto ret; /* success */
101 xioctl(fd, PIO_FONT, buf);
107 static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
109 struct unimapinit advice;
110 struct unimapdesc ud;
116 maxct = tailsz; /* more than enough */
117 up = xmalloc(maxct * sizeof(struct unipair));
119 for (glyph = 0; glyph < fontsize; glyph++) {
120 while (tailsz >= 2) {
121 unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
124 if (unicode == PSF_SEPARATOR)
126 up[ct].unicode = unicode;
127 up[ct].fontpos = glyph;
132 /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
133 this printf did not work on many kernels */
135 advice.advised_hashsize = 0;
136 advice.advised_hashstep = 0;
137 advice.advised_hashlevel = 0;
138 xioctl(fd, PIO_UNIMAPCLR, &advice);
141 xioctl(fd, PIO_UNIMAP, &ud);
144 static void do_load(int fd, struct psf_header *psfhdr, size_t len)
149 unsigned head0, head = head;
151 /* test for psf first */
152 if (len >= sizeof(struct psf_header) && PSF_MAGIC_OK(psfhdr)) {
153 if (psfhdr->mode > PSF_MAXMODE)
154 bb_error_msg_and_die("unsupported psf file mode");
155 fontsize = ((psfhdr->mode & PSF_MODE512) ? 512 : 256);
156 #if !defined(PIO_FONTX) || defined(__sparc__)
158 bb_error_msg_and_die("only fontsize 256 supported");
160 hastable = (psfhdr->mode & PSF_MODEHASTAB);
161 unit = psfhdr->charsize;
162 head0 = sizeof(struct psf_header);
164 head = head0 + fontsize * unit;
165 if (head > len || (!hastable && head != len))
166 bb_error_msg_and_die("input file: bad length");
168 /* file with three code pages? */
175 bb_error_msg_and_die("input file: bad length");
183 do_loadfont(fd, (unsigned char *)psfhdr + head0, unit, fontsize);
185 do_loadtable(fd, (unsigned char *)psfhdr + head, len - head, fontsize);
189 int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
190 int loadfont_main(int argc UNUSED_PARAM, char **argv)
193 struct psf_header *psfhdr;
195 // no arguments allowed!
196 opt_complementary = "=0";
200 * We used to look at the length of the input file
201 * with stat(); now that we accept compressed files,
202 * just read the entire file.
204 len = 32*1024; // can't be larger
205 psfhdr = xmalloc_read(STDIN_FILENO, &len);
206 // xmalloc_open_zipped_read_close(filename, &len);
208 bb_perror_msg_and_die("error reading input font");
209 do_load(get_console_fd_or_die(), psfhdr, len);
220 setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig]
221 [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console]
224 -h NN Override font height
226 Save previous font in file
228 Save previous font and Unicode map in file
230 Store console map in file
232 Save previous Unicode map in file
234 Load console map or Unicode console map from file
236 Load Unicode table describing the font from file
241 0x80 U+0410 # CYRILLIC CAPITAL LETTER A
242 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE
243 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE
245 Set the font for the indicated console
250 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
251 static int ctoi(char *s)
253 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
256 if (s[0] == 'U' && s[1] == '+') {
262 return xstrtoul(s, 0);
266 int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
267 int setfont_main(int argc UNUSED_PARAM, char **argv)
272 struct psf_header *psfhdr;
274 const char *tty_name = CURRENT_TTY;
276 opt_complementary = "=1";
277 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
280 fd = xopen(tty_name, O_NONBLOCK);
282 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
283 if (*argv[0] != '/') {
284 // goto default fonts location. don't die if doesn't exist
285 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
289 len = 32*1024; // can't be larger
290 psfhdr = xmalloc_open_zipped_read_close(*argv, &len);
292 bb_simple_perror_msg_and_die(*argv);
293 do_load(fd, psfhdr, len);
295 // load the screen map, if any
296 if (opts & 1) { // -m
297 unsigned mode = PIO_SCRNMAP;
300 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
301 if (mapfilename[0] != '/') {
302 // goto default keymaps location
303 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
307 map = xmalloc_open_zipped_read_close(mapfilename, &len);
309 bb_simple_perror_msg_and_die(mapfilename);
310 // file size is 256 or 512 bytes? -> assume binary map
311 if (len == E_TABSZ || len == 2*E_TABSZ) {
312 if (len == 2*E_TABSZ)
313 mode = PIO_UNISCRNMAP;
315 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
316 // assume textual Unicode console maps:
317 // 0x00 U+0000 # NULL (NUL)
318 // 0x01 U+0001 # START OF HEADING (SOH)
319 // 0x02 U+0002 # START OF TEXT (STX)
320 // 0x03 U+0003 # END OF TEXT (ETX)
326 if (ENABLE_FEATURE_CLEAN_UP)
328 map = xmalloc(E_TABSZ * sizeof(unsigned short));
330 #define unicodes ((unsigned short *)map)
332 for (i = 0; i < E_TABSZ; i++)
333 unicodes[i] = 0xf000 + i;
335 parser = config_open(mapfilename);
336 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
337 // parse code/value pair
338 int a = ctoi(token[0]);
339 int b = ctoi(token[1]);
340 if (a < 0 || a >= E_TABSZ
341 || b < 0 || b > 65535
343 bb_error_msg_and_die("map format");
347 // unicode character is met?
349 mode = PIO_UNISCRNMAP;
351 if (ENABLE_FEATURE_CLEAN_UP)
352 config_close(parser);
354 if (mode != PIO_UNISCRNMAP) {
355 #define asciis ((unsigned char *)map)
356 for (i = 0; i < E_TABSZ; i++)
357 asciis[i] = unicodes[i];
362 #endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
365 xioctl(fd, mode, map);
367 if (ENABLE_FEATURE_CLEAN_UP)