xref: /openbsd-src/sys/dev/wsfont/wsfont.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: wsfont.c,v 1.36 2014/07/12 18:48:53 tedu Exp $ */
2 /*	$NetBSD: wsfont.c,v 1.17 2001/02/07 13:59:24 ad Exp $	*/
3 
4 /*-
5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Andrew Doran.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/time.h>
37 #include <sys/malloc.h>
38 #include <sys/queue.h>
39 
40 #include <dev/wscons/wsdisplayvar.h>
41 #include <dev/wscons/wsconsio.h>
42 #include <dev/wsfont/wsfont.h>
43 
44 #include "wsfont_glue.h"	/* NRASOPS_ROTATION */
45 
46 #undef HAVE_FONT
47 
48 #ifdef FONT_QVSS8x15
49 #define HAVE_FONT 1
50 #include <dev/wsfont/qvss8x15.h>
51 #endif
52 
53 #ifdef FONT_LUCIDA16x29
54 #define HAVE_FONT 1
55 #include <dev/wsfont/lucida16x29.h>
56 #endif
57 
58 #ifdef FONT_VT220L8x8
59 #define HAVE_FONT 1
60 #include <dev/wsfont/vt220l8x8.h>
61 #endif
62 
63 #ifdef FONT_VT220L8x10
64 #define HAVE_FONT 1
65 #include <dev/wsfont/vt220l8x10.h>
66 #endif
67 
68 #ifdef FONT_SONY8x16
69 #define HAVE_FONT 1
70 #include <dev/wsfont/sony8x16.h>
71 #endif
72 
73 #ifdef FONT_SONY12x24
74 #define HAVE_FONT 1
75 #include <dev/wsfont/sony12x24.h>
76 #endif
77 
78 #ifdef FONT_OMRON12x20
79 #define HAVE_FONT 1
80 #include <dev/wsfont/omron12x20.h>
81 #endif
82 
83 #ifdef FONT_BOLD8x16
84 #define HAVE_FONT 1
85 #include <dev/wsfont/bold8x16.h>
86 #endif
87 
88 #ifdef FONT_GALLANT12x22
89 #define HAVE_FONT 1
90 #endif
91 
92 #ifdef FONT_BOLD8x16_ISO1
93 #define HAVE_FONT 1
94 #endif
95 
96 /*
97  * Make sure we always have at least one font.
98  * Sparc, sparc64 always provide a 8x16 font and a larger 12x22 font.
99  * Other platforms also provide both, but the 12x22 font is omitted if
100  * option SMALL_KERNEL.
101  */
102 #ifndef HAVE_FONT
103 #define HAVE_FONT 1
104 
105 #define	FONT_BOLD8x16_ISO1
106 #if defined(__sparc__) || defined(__sparc64__) || defined(__luna88k__) || !defined(SMALL_KERNEL)
107 #define	FONT_GALLANT12x22
108 #endif
109 
110 #endif	/* HAVE_FONT */
111 
112 #ifdef FONT_BOLD8x16_ISO1
113 #include <dev/wsfont/bold8x16-iso1.h>
114 #endif
115 
116 #ifdef FONT_GALLANT12x22
117 #include <dev/wsfont/gallant12x22.h>
118 #endif
119 
120 struct font {
121 	TAILQ_ENTRY(font) chain;
122 	struct	wsdisplay_font *font;
123 	u_short	lockcount;
124 	u_short	cookie;
125 	u_short	flg;
126 };
127 TAILQ_HEAD(, font) list;
128 
129 /* Our list of built-in fonts */
130 static struct font builtin_fonts[] = {
131 #define BUILTIN_FONT(f, c) \
132 	{ .font = &(f), .cookie = (c), .lockcount = 0, \
133 	  .flg = WSFONT_STATIC | WSFONT_BUILTIN }
134 #ifdef FONT_BOLD8x16
135 	BUILTIN_FONT(bold8x16, 1),
136 #endif
137 #ifdef FONT_BOLD8x16_ISO1
138 	BUILTIN_FONT(bold8x16_iso1, 2),
139 #endif
140 #ifdef FONT_COURIER11x18
141 	BUILTIN_FONT(courier11x18, 3),
142 #endif
143 #ifdef FONT_GALLANT12x22
144 	BUILTIN_FONT(gallant12x22, 4),
145 #endif
146 #ifdef FONT_LUCIDA16x29
147 	BUILTIN_FONT(lucida16x29, 5),
148 #endif
149 #ifdef FONT_QVSS8x15
150 	BUILTIN_FONT(qvss8x15, 6),
151 #endif
152 #ifdef FONT_VT220L8x8
153 	BUILTIN_FONT(vt220l8x8, 7),
154 #endif
155 #ifdef FONT_VT220L8x10
156 	BUILTIN_FONT(vt220l8x10, 8),
157 #endif
158 #ifdef FONT_SONY8x16
159 	BUILTIN_FONT(sony8x16, 9),
160 #endif
161 #ifdef FONT_SONY12x24
162 	BUILTIN_FONT(sony12x24, 10),
163 #endif
164 #ifdef FONT_OMRON12x20
165 	BUILTIN_FONT(omron12x20, 11),
166 #endif
167 #undef BUILTIN_FONT
168 };
169 
170 #if !defined(SMALL_KERNEL) || defined(__alpha__)
171 
172 /* Reverse the bit order in a byte */
173 static const u_char reverse[256] = {
174 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
175 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
176 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
177 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
178 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
179 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
180 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
181 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
182 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
183 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
184 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
185 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
186 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
187 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
188 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
189 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
190 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
191 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
192 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
193 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
194 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
195 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
196 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
197 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
198 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
199 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
200 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
201 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
202 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
203 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
204 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
205 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
206 };
207 
208 #endif
209 
210 static struct font *wsfont_find0(int);
211 
212 #if !defined(SMALL_KERNEL) || defined(__alpha__)
213 
214 /*
215  * Reverse the bit order of a font
216  */
217 static void	wsfont_revbit(struct wsdisplay_font *);
218 static void
219 wsfont_revbit(struct wsdisplay_font *font)
220 {
221 	u_char *p, *m;
222 
223 	p = (u_char *)font->data;
224 	m = p + font->stride * font->numchars * font->fontheight;
225 
226 	for (; p < m; p++)
227 		*p = reverse[*p];
228 }
229 
230 #endif
231 
232 #if !defined(SMALL_KERNEL)
233 
234 /*
235  * Reverse the byte order of a font
236  */
237 static void	wsfont_revbyte(struct wsdisplay_font *);
238 static void
239 wsfont_revbyte(struct wsdisplay_font *font)
240 {
241 	int x, l, r, nr;
242 	u_char *rp;
243 
244 	if (font->stride == 1)
245 		return;
246 
247 	rp = (u_char *)font->data;
248 	nr = font->numchars * font->fontheight;
249 
250 	while (nr--) {
251 		l = 0;
252 		r = font->stride - 1;
253 
254 		while (l < r) {
255 			x = rp[l];
256 			rp[l] = rp[r];
257 			rp[r] = x;
258 			l++, r--;
259 		}
260 
261 		rp += font->stride;
262 	}
263 }
264 
265 #endif
266 
267 /*
268  * Enumerate the list of fonts
269  */
270 void
271 wsfont_enum(int (*cb)(void *, struct wsdisplay_font *), void *cbarg)
272 {
273 	struct font *ent;
274 	int s;
275 
276 	s = splhigh();
277 
278 	TAILQ_FOREACH(ent, &list, chain)
279 		if (cb(cbarg, ent->font) != 0)
280 			break;
281 
282 	splx(s);
283 }
284 
285 #if NRASOPS_ROTATION > 0
286 
287 struct wsdisplay_font *wsfont_rotate_internal(struct wsdisplay_font *);
288 
289 struct wsdisplay_font *
290 wsfont_rotate_internal(struct wsdisplay_font *font)
291 {
292 	int b, n, r, newstride;
293 	struct wsdisplay_font *newfont;
294 	char *newbits;
295 
296 	/* Duplicate the existing font... */
297 	newfont = malloc(sizeof *font, M_DEVBUF, M_WAITOK);
298 
299 	bcopy(font, newfont, sizeof *font);
300 	newfont->cookie = NULL;
301 
302 	/* Allocate a buffer big enough for the rotated font. */
303 	newstride = (font->fontheight + 7) / 8;
304 	newbits = malloc(newstride * font->fontwidth * font->numchars,
305 	    M_DEVBUF, M_WAITOK | M_ZERO);
306 
307 	/* Rotate the font a bit at a time. */
308 	for (n = 0; n < font->numchars; n++) {
309 		char *ch = font->data + (n * font->stride * font->fontheight);
310 
311 		for (r = 0; r < font->fontheight; r++) {
312 			for (b = 0; b < font->fontwidth; b++) {
313 				unsigned char *rb;
314 
315 				rb = ch + (font->stride * r) + (b / 8);
316 				if (*rb & (0x80 >> (b % 8))) {
317 					unsigned char *rrb;
318 
319 					rrb = newbits + newstride - 1 - (r / 8)
320 					    + (n * newstride * font->fontwidth)
321 					    + (newstride * b);
322 					*rrb |= (1 << (r % 8));
323 				}
324 			}
325 		}
326 	}
327 
328 	newfont->data = newbits;
329 
330 	/* Update font sizes. */
331 	newfont->stride = newstride;
332 	newfont->fontwidth = font->fontheight;
333 	newfont->fontheight = font->fontwidth;
334 
335 	if (wsfont_add(newfont, 0) != 0) {
336 		/*
337 		 * If we seem to have rotated this font already, drop the
338 		 * new one...
339 		 */
340 		free(newbits, M_DEVBUF, 0);
341 		free(newfont, M_DEVBUF, 0);
342 		newfont = NULL;
343 	}
344 
345 	return (newfont);
346 }
347 
348 int
349 wsfont_rotate(int cookie)
350 {
351 	int s, ncookie;
352 	struct wsdisplay_font *font;
353 	struct font *origfont;
354 
355 	s = splhigh();
356 	origfont = wsfont_find0(cookie);
357 	splx(s);
358 
359 	font = wsfont_rotate_internal(origfont->font);
360 	if (font == NULL)
361 		return (-1);
362 
363 	ncookie = wsfont_find(font->name, font->fontwidth, font->fontheight,
364 	    font->stride);
365 
366 	return (ncookie);
367 }
368 
369 #endif	/* NRASOPS_ROTATION */
370 
371 /*
372  * Initialize list with WSFONT_BUILTIN fonts
373  */
374 void
375 wsfont_init(void)
376 {
377 	static int again;
378 	unsigned int i;
379 
380 	if (again != 0)
381 		return;
382 	again = 1;
383 
384 	TAILQ_INIT(&list);
385 
386 	for (i = 0; i < nitems(builtin_fonts); i++) {
387 		TAILQ_INSERT_TAIL(&list, &builtin_fonts[i], chain);
388 	}
389 }
390 
391 /*
392  * Find a font by cookie. Called at splhigh.
393  */
394 static struct font *
395 wsfont_find0(int cookie)
396 {
397 	struct font *ent;
398 
399 	TAILQ_FOREACH(ent, &list, chain)
400 		if (ent->cookie == cookie)
401 			return (ent);
402 
403 	return (NULL);
404 }
405 
406 /*
407  * Find a font.
408  */
409 int
410 wsfont_find(const char *name, int width, int height, int stride)
411 {
412 	struct font *ent;
413 	int s;
414 
415 	s = splhigh();
416 
417 	TAILQ_FOREACH(ent, &list, chain) {
418 		if (height != 0 && ent->font->fontheight != height)
419 			continue;
420 
421 		if (width != 0 && ent->font->fontwidth != width)
422 			continue;
423 
424 		if (stride != 0 && ent->font->stride != stride)
425 			continue;
426 
427 		if (name != NULL && strcmp(ent->font->name, name) != 0)
428 			continue;
429 
430 		splx(s);
431 		return (ent->cookie);
432 	}
433 
434 	splx(s);
435 	return (-1);
436 }
437 
438 /*
439  * Add a font to the list.
440  */
441 int
442 wsfont_add(struct wsdisplay_font *font, int copy)
443 {
444 	static int cookiegen = 666;
445 	struct font *ent;
446 	int s;
447 
448 	s = splhigh();
449 
450 	/* Don't allow exact duplicates */
451 	if (wsfont_find(font->name, font->fontwidth, font->fontheight,
452 	    font->stride) >= 0) {
453 		splx(s);
454 		return (-1);
455 	}
456 
457 	ent = (struct font *)malloc(sizeof *ent, M_DEVBUF, M_WAITOK);
458 
459 	ent->lockcount = 0;
460 	ent->flg = 0;
461 	ent->cookie = cookiegen++;
462 
463 	/*
464 	 * If we are coming from a WSDISPLAYIO_LDFONT ioctl, we need to
465 	 * make a copy of the wsdisplay_font struct, but not of font->bits.
466 	 */
467 	if (copy) {
468 		ent->font = (struct wsdisplay_font *)malloc(sizeof *ent->font,
469 		    M_DEVBUF, M_WAITOK);
470 		memcpy(ent->font, font, sizeof(*ent->font));
471 		ent->flg = 0;
472 	} else {
473 		ent->font = font;
474 		ent->flg = WSFONT_STATIC;
475 	}
476 
477 	/* Now link into the list and return */
478 	TAILQ_INSERT_TAIL(&list, ent, chain);
479 	splx(s);
480 	return (0);
481 }
482 
483 /*
484  * Remove a font.
485  */
486 #ifdef notyet
487 int
488 wsfont_remove(int cookie)
489 {
490 	struct font *ent;
491 	int s;
492 
493 	s = splhigh();
494 
495 	if ((ent = wsfont_find0(cookie)) == NULL) {
496 		splx(s);
497 		return (-1);
498 	}
499 
500 	if ((ent->flg & WSFONT_BUILTIN) != 0 || ent->lockcount != 0) {
501 		splx(s);
502 		return (-1);
503 	}
504 
505 	/* Don't free statically allocated font data */
506 	if ((ent->flg & WSFONT_STATIC) != 0) {
507 		free(ent->font->data, M_DEVBUF, 0);
508 		free(ent->font, M_DEVBUF, 0);
509 	}
510 
511 	/* Remove from list, free entry */
512 	TAILQ_REMOVE(&list, ent, chain);
513 	free(ent, M_DEVBUF, 0);
514 	splx(s);
515 	return (0);
516 }
517 #endif
518 
519 /*
520  * Lock a given font and return new lockcount. This fails if the cookie
521  * is invalid, or if the font is already locked and the bit/byte order
522  * requested by the caller differs.
523  */
524 int
525 wsfont_lock(int cookie, struct wsdisplay_font **ptr, int bitorder,
526     int byteorder)
527 {
528 	struct font *ent;
529 	int s, lc;
530 
531 	s = splhigh();
532 
533 	if ((ent = wsfont_find0(cookie)) != NULL) {
534 		if (bitorder && bitorder != ent->font->bitorder) {
535 #if !defined(SMALL_KERNEL) || defined(__alpha__)
536 			if (ent->lockcount) {
537 				splx(s);
538 				return (-1);
539 			}
540 			wsfont_revbit(ent->font);
541 			ent->font->bitorder = bitorder;
542 #else
543 			splx(s);
544 			return (-1);
545 #endif
546 		}
547 
548 		if (byteorder && byteorder != ent->font->byteorder) {
549 #if !defined(SMALL_KERNEL)
550 			if (ent->lockcount) {
551 				splx(s);
552 				return (-1);
553 			}
554 			wsfont_revbyte(ent->font);
555 			ent->font->byteorder = byteorder;
556 #else
557 			splx(s);
558 			return (-1);
559 #endif
560 		}
561 
562 		lc = ++ent->lockcount;
563 		*ptr = ent->font;
564 	} else
565 		lc = -1;
566 
567 	splx(s);
568 	return (lc);
569 }
570 
571 /*
572  * Unlock a given font and return new lockcount.
573  */
574 int
575 wsfont_unlock(int cookie)
576 {
577 	struct font *ent;
578 	int s, lc;
579 
580 	s = splhigh();
581 
582 	if ((ent = wsfont_find0(cookie)) != NULL) {
583 		if (ent->lockcount == 0)
584 			panic("wsfont_unlock: font not locked");
585 		lc = --ent->lockcount;
586 	} else
587 		lc = -1;
588 
589 	splx(s);
590 	return (lc);
591 }
592 
593 #if !defined(SMALL_KERNEL)
594 
595 /*
596  * Unicode to font encoding mappings
597  */
598 
599 /*
600  * To save memory, font encoding tables use a two level lookup.
601  * First the high byte of the Unicode is used to lookup the level 2
602  * table, then the low byte indexes that table.  Level 2 tables that are
603  * not needed are omitted (NULL), and both level 1 and level 2 tables
604  * have base and size attributes to keep their size down.
605  */
606 
607 struct wsfont_level1_glyphmap {
608 	struct wsfont_level2_glyphmap **level2;
609 	int base;	/* High byte for first level2 entry	*/
610 	int size;	/* Number of level2 entries		*/
611 };
612 
613 struct wsfont_level2_glyphmap {
614 	int base;	/* Low byte for first character		*/
615 	int size;	/* Number of characters			*/
616 	void *chars;	/* Pointer to character number entries  */
617 	int width;	/* Size of each entry in bytes (1,2,4)  */
618 };
619 
620 /*
621  * IBM 437 maps
622  */
623 
624 static u_int8_t
625 ibm437_chars_0[] = {
626 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
627 	16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
628 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
629 	48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
630 	64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
631 	80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
632 	96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,
633 	112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
634 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
635 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
636 	255,173,155,156, 0, 157, 0,  0,  0,  0, 166,174,170, 0,  0,  0,
637 	 0, 241,253, 0,  0,  0,  0, 249, 0,  0, 167,175,172,171, 0, 168,
638 	 0,  0,  0,  0, 142,143,146,128, 0, 144, 0,  0,  0,  0,  0,  0,
639 	 0, 165, 0,  0,  0,  0, 153, 0,  0,  0,  0,  0, 154, 0,  0,  0,
640 	133,160,131, 0, 132,134,145,135,138,130,136,137,141,161,140,139,
641 	 0, 164,149,162,147, 0, 148,246, 0, 151,163,150,129, 0,  0, 152
642 },
643 ibm437_chars_1[] = {
644 	159
645 },
646 ibm437_chars_3[] = {
647 	226, 0,  0,  0,  0, 233, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
648 	228, 0,  0, 232, 0,  0, 234, 0,  0,  0,  0,  0,  0,  0, 224,225,
649 	 0, 235,238, 0,  0,  0,  0,  0,  0, 230, 0,  0,  0, 227, 0,  0,
650 	229,231
651 },
652 ibm437_chars_32[] = {
653 	252, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
654 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
655 	 0,  0,  0,  0,  0,  0,  0,  0, 158
656 },
657 ibm437_chars_34[] = {
658 	237, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
659 	 0,  0,  0, 248,250,251, 0,  0,  0, 236, 0,  0,  0,  0,  0,  0,
660 	 0,  0,  0,  0, 239, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
661 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
662 	 0,  0,  0, 247, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
663 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,  0,  0,243,
664 	242
665 },
666 ibm437_chars_35[] = {
667 	169, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
668 	244,245
669 },
670 ibm437_chars_37[] = {
671 	196,205,179,186, 0,  0,  0,  0,  0,  0,  0,  0, 218,213,214,201,
672 	191,184,183,187,192,212,211,200,217,190,189,188,195,198, 0,  0,
673 	199, 0,  0, 204,180,181, 0,  0, 182, 0,  0, 185,194, 0,  0, 209,
674 	210, 0,  0, 203,193, 0,  0, 207,208, 0,  0, 202,197, 0,  0, 216,
675 	 0,  0, 215, 0,  0,  0,  0,  0,  0,  0,  0, 206, 0,  0,  0,  0,
676 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
677 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
678 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
679 	223, 0,  0,  0, 220, 0,  0,  0, 219, 0,  0,  0, 221, 0,  0,  0,
680 	222,176,177,178, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
681 	254
682 };
683 
684 static struct wsfont_level2_glyphmap
685 ibm437_level2_0 = { 0, 256, ibm437_chars_0, 1 },
686 ibm437_level2_1 = { 146, 1, ibm437_chars_1, 1 },
687 ibm437_level2_3 = { 147, 50, ibm437_chars_3, 1 },
688 ibm437_level2_32 = { 127, 41, ibm437_chars_32, 1 },
689 ibm437_level2_34 = { 5, 97, ibm437_chars_34, 1 },
690 ibm437_level2_35 = { 16, 18, ibm437_chars_35, 1 },
691 ibm437_level2_37 = { 0, 161, ibm437_chars_37, 1 };
692 
693 static struct wsfont_level2_glyphmap *ibm437_level1[] = {
694 	&ibm437_level2_0, &ibm437_level2_1, NULL, &ibm437_level2_3,
695 	NULL, NULL, NULL, NULL,
696 	NULL, NULL, NULL, NULL,
697 	NULL, NULL, NULL, NULL,
698 	NULL, NULL, NULL, NULL,
699 	NULL, NULL, NULL, NULL,
700 	NULL, NULL, NULL, NULL,
701 	NULL, NULL, NULL, NULL,
702 	&ibm437_level2_32, NULL, &ibm437_level2_34, &ibm437_level2_35,
703 	NULL, &ibm437_level2_37
704 };
705 
706 static struct wsfont_level1_glyphmap encodings[] = {
707 	/* WSDISPLAY_FONTENC_ISO */
708 	{ NULL, 0, 0 },
709 	/* WSDISPLAY_FONTENC_IBM */
710 	{ ibm437_level1, 0, nitems(ibm437_level1) }
711 };
712 
713 #endif	/* !SMALL_KERNEL */
714 
715 /*
716  * Remap Unicode character to glyph
717  */
718 int
719 wsfont_map_unichar(struct wsdisplay_font *font, int c)
720 {
721 	if (font->encoding == WSDISPLAY_FONTENC_ISO)
722 		return (c);
723 
724 #if !defined(SMALL_KERNEL)
725 	if (font->encoding >= 0 && font->encoding < nitems(encodings)) {
726 		int hi = (c >> 8), lo = c & 255;
727 		struct wsfont_level1_glyphmap *map1 =
728 		    &encodings[font->encoding];
729 		struct wsfont_level2_glyphmap *map2;
730 
731 		hi -= map1->base;
732 
733 		if (hi >= 0 && hi < map1->size &&
734 		    (map2 = map1->level2[hi]) != NULL) {
735 			lo -= map2->base;
736 
737 			if (lo >= 0 && lo < map2->size) {
738 				switch (map2->width) {
739 				case 1:
740 					c = (((u_int8_t *)map2->chars)[lo]);
741 					break;
742 				case 2:
743 					c = (((u_int16_t *)map2->chars)[lo]);
744 					break;
745 				case 4:
746 					c = (((u_int32_t *)map2->chars)[lo]);
747 					break;
748 				}
749 
750 				if (c != 0 || lo == 0)
751 					return (c);
752 			}
753 		}
754 	}
755 #endif	/* !SMALL_KERNEL */
756 
757 	return (-1);
758 }
759