1170754Sdelphij/*-
2170754Sdelphij * Copyright (c) 1999 FreeBSD(98) Porting Team.
3170754Sdelphij * All rights reserved.
4170754Sdelphij *
5170754Sdelphij * Redistribution and use in source and binary forms, with or without
6170754Sdelphij * modification, are permitted provided that the following conditions
7170754Sdelphij * are met:
8170754Sdelphij * 1. Redistributions of source code must retain the above copyright
9170754Sdelphij *    notice, this list of conditions and the following disclaimer as
10170754Sdelphij *    the first lines of this file unmodified.
11170754Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12170754Sdelphij *    notice, this list of conditions and the following disclaimer in the
13170754Sdelphij *    documentation and/or other materials provided with the distribution.
14170754Sdelphij *
15170754Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16170754Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17170754Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18170754Sdelphij * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19170754Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20170754Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21170754Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22170754Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23170754Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24170754Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25170754Sdelphij *
26170754Sdelphij * $FreeBSD: releng/11.0/sys/pc98/cbus/scterm-sck.c 298352 2016-04-20 15:45:55Z pfg $
27170754Sdelphij */
28170754Sdelphij
29170754Sdelphij#include "opt_syscons.h"
30170754Sdelphij
31170754Sdelphij#include <sys/param.h>
32170754Sdelphij#include <sys/systm.h>
33170754Sdelphij#include <sys/kernel.h>
34170754Sdelphij#include <sys/module.h>
35170754Sdelphij#include <sys/consio.h>
36170754Sdelphij
37170754Sdelphij#include <machine/pc/display.h>
38170754Sdelphij
39170754Sdelphij#include <dev/syscons/syscons.h>
40170754Sdelphij#include <pc98/cbus/sctermvar.h>
41170754Sdelphij
42170754Sdelphij#define MAX_ESC_PAR	5
43170754Sdelphij
44170754Sdelphij#ifdef KANJI
45170754Sdelphij#define IS_KTYPE_ASCII_or_HANKAKU(A)	(!((A) & 0xee))
46170754Sdelphij#define IS_KTYPE_KANA(A)		((A) & 0x11)
47170754Sdelphij#define KTYPE_MASK_CTRL(A)		((A) &= 0xF0)
48170754Sdelphij#endif /* KANJI */
49170754Sdelphij
50170754Sdelphij/* attribute flags */
51170754Sdelphijtypedef struct {
52170754Sdelphij	u_short		fg;			/* foreground color */
53170754Sdelphij	u_short		bg;			/* background color */
54170754Sdelphij} color_t;
55170754Sdelphij
56170754Sdelphijtypedef struct {
57170754Sdelphij	int		flags;
58170754Sdelphij#define SCTERM_BUSY	(1 << 0)
59170754Sdelphij	int		esc;
60170754Sdelphij	int		num_param;
61170754Sdelphij	int		last_param;
62170754Sdelphij	int		param[MAX_ESC_PAR];
63170754Sdelphij	int		saved_xpos;
64170754Sdelphij	int		saved_ypos;
65170754Sdelphij
66170754Sdelphij#ifdef KANJI
67170754Sdelphij	u_char		kanji_1st_char;
68170754Sdelphij	u_char		kanji_type;
69170754Sdelphij#define KTYPE_ASCII	0			/* ASCII */
70170754Sdelphij#define KTYPE_KANA	1			/* HANKAKU */
71170754Sdelphij#define KTYPE_JKANA	0x10			/* JIS HANKAKU */
72170754Sdelphij#define KTYPE_7JIS	0x20			/* JIS */
73170754Sdelphij#define KTYPE_SJIS	2			/* Shift JIS */
74170754Sdelphij#define KTYPE_UJIS	4			/* UJIS */
75170754Sdelphij#define KTYPE_SUKANA	3			/* Shift JIS or UJIS HANKAKU */
76170754Sdelphij#define KTYPE_SUJIS	6			/* SHift JIS or UJIS */
77170754Sdelphij#define KTYPE_KANIN	0x80			/* Kanji Invoke sequence */
78170754Sdelphij#define KTYPE_ASCIN	0x40			/* ASCII Invoke sequence */
79170754Sdelphij#endif /* KANJI */
80170754Sdelphij
81170754Sdelphij	int		attr_mask;		/* current logical attr mask */
82170754Sdelphij#define NORMAL_ATTR	0x00
83170754Sdelphij#define BLINK_ATTR	0x01
84170754Sdelphij#define BOLD_ATTR	0x02
85170754Sdelphij#define UNDERLINE_ATTR	0x04
86170754Sdelphij#define REVERSE_ATTR	0x08
87170754Sdelphij#define FG_CHANGED	0x10
88170754Sdelphij#define BG_CHANGED	0x20
89170754Sdelphij	int		cur_attr;		/* current hardware attr word */
90170754Sdelphij	color_t		cur_color;		/* current hardware color */
91170754Sdelphij	color_t		std_color;		/* normal hardware color */
92170754Sdelphij	color_t		rev_color;		/* reverse hardware color */
93170754Sdelphij	color_t		dflt_std_color;		/* default normal color */
94170754Sdelphij	color_t		dflt_rev_color;		/* default reverse color */
95170754Sdelphij} term_stat;
96170754Sdelphij
97170754Sdelphijstatic sc_term_init_t		scterm_init;
98170754Sdelphijstatic sc_term_term_t		scterm_term;
99170754Sdelphijstatic sc_term_puts_t		scterm_puts;
100170754Sdelphijstatic sc_term_ioctl_t		scterm_ioctl;
101170754Sdelphijstatic sc_term_reset_t		scterm_reset;
102170754Sdelphijstatic sc_term_default_attr_t	scterm_default_attr;
103170754Sdelphijstatic sc_term_clear_t		scterm_clear;
104170754Sdelphijstatic sc_term_notify_t		scterm_notify;
105170754Sdelphijstatic sc_term_input_t		scterm_input;
106170754Sdelphijstatic sc_term_fkeystr_t	scterm_fkeystr;
107170754Sdelphij
108170754Sdelphijstatic sc_term_sw_t sc_term_sc = {
109170754Sdelphij	{ NULL, NULL },
110170754Sdelphij	"sck",					/* emulator name */
111170754Sdelphij	"syscons kanji terminal",		/* description */
112170754Sdelphij	"*",					/* matching renderer, any :-) */
113170754Sdelphij	sizeof(term_stat),			/* softc size */
114170754Sdelphij	0,
115170754Sdelphij	scterm_init,
116170754Sdelphij	scterm_term,
117170754Sdelphij	scterm_puts,
118170754Sdelphij	scterm_ioctl,
119170754Sdelphij	scterm_reset,
120170754Sdelphij	scterm_default_attr,
121170754Sdelphij	scterm_clear,
122170754Sdelphij	scterm_notify,
123170754Sdelphij	scterm_input,
124170754Sdelphij	scterm_fkeystr,
125170754Sdelphij};
126170754Sdelphij
127170754SdelphijSCTERM_MODULE(sc, sc_term_sc);
128170754Sdelphij
129170754Sdelphijstatic term_stat	reserved_term_stat;
130170754Sdelphijstatic int		default_kanji = UJIS;
131170754Sdelphijstatic void		scterm_scan_esc(scr_stat *scp, term_stat *tcp,
132170754Sdelphij					u_char c);
133170754Sdelphijstatic int		mask2attr(term_stat *tcp);
134170754Sdelphij
135170754Sdelphij#ifdef KANJI
136170754Sdelphijstatic inline u_char
137170754Sdelphijiskanji1(u_char mode, u_char c)
138170754Sdelphij{
139170754Sdelphij	if (c > 0x80) {
140170754Sdelphij		if ((c >= 0xa1) && (c <= 0xdf)) {
141170754Sdelphij			if (default_kanji == UJIS) {
142170754Sdelphij				/* UJIS */
143170754Sdelphij				return KTYPE_UJIS;
144170754Sdelphij			}
145170754Sdelphij			if (default_kanji == SJIS) {
146170754Sdelphij				/* SJIS HANKAKU */
147170754Sdelphij				return KTYPE_KANA;
148170754Sdelphij			}
149170754Sdelphij		}
150170754Sdelphij
151170754Sdelphij		if (c <= 0x9f) {
152170754Sdelphij			if (c == 0x8e) {
153170754Sdelphij				/* SJIS or UJIS HANKAKU */
154170754Sdelphij				return KTYPE_SUKANA;
155170754Sdelphij			}
156170754Sdelphij
157170754Sdelphij			/* SJIS */
158170754Sdelphij			default_kanji = SJIS;
159170754Sdelphij			return KTYPE_SJIS;
160170754Sdelphij		}
161170754Sdelphij
162170754Sdelphij		if ((c >= 0xe0) && (c <= 0xef)) {
163170754Sdelphij			/* SJIS or UJIS */
164170754Sdelphij			return KTYPE_SUJIS;
165170754Sdelphij		}
166170754Sdelphij
167170754Sdelphij		if ((c >= 0xf0) && (c <= 0xfe)) {
168170754Sdelphij			/* UJIS */
169170754Sdelphij			default_kanji = UJIS;
170170754Sdelphij			return KTYPE_UJIS;
171170754Sdelphij		}
172170754Sdelphij	} else {
173170754Sdelphij		if ((mode == KTYPE_7JIS) && (c >= 0x21) && (c <= 0x7e)) {
174170754Sdelphij			/* JIS */
175170754Sdelphij			default_kanji = UJIS;
176170754Sdelphij			return KTYPE_7JIS;
177170754Sdelphij		}
178170754Sdelphij
179170754Sdelphij		if ((mode == KTYPE_JKANA) && (c >= 0x21) && (c <= 0x5f)) {
180170754Sdelphij			/* JIS HANKAKU */
181170754Sdelphij			default_kanji = UJIS;
182170754Sdelphij			return KTYPE_JKANA;
183170754Sdelphij		}
184170754Sdelphij	}
185170754Sdelphij
186170754Sdelphij	return KTYPE_ASCII;
187170754Sdelphij}
188170754Sdelphij
189170754Sdelphijstatic inline u_char
190170754Sdelphijiskanji2(u_char mode, u_char c)
191170754Sdelphij{
192170754Sdelphij	switch (mode) {
193170754Sdelphij	case KTYPE_7JIS:
194170754Sdelphij		if ((c >= 0x21) && (c <= 0x7e)) {
195170754Sdelphij			/* JIS */
196170754Sdelphij			return KTYPE_7JIS;
197170754Sdelphij		}
198170754Sdelphij		break;
199170754Sdelphij	case KTYPE_SJIS:
200170754Sdelphij		if ((c >= 0x40) && (c <= 0xfc) && (c != 0x7f)) {
201170754Sdelphij			/* SJIS */
202170754Sdelphij			return KTYPE_SJIS;
203170754Sdelphij		}
204170754Sdelphij		break;
205170754Sdelphij	case KTYPE_UJIS:
206170754Sdelphij		if ((c >= 0xa1) && (c <= 0xfe)) {
207170754Sdelphij			/* UJIS */
208170754Sdelphij			return KTYPE_UJIS;
209170754Sdelphij		}
210170754Sdelphij		break;
211170754Sdelphij	case KTYPE_SUKANA:
212170754Sdelphij		if ((c >= 0xa1) && (c <= 0xdf) && (default_kanji == UJIS)) {
213170754Sdelphij			/* UJIS HANKAKU */
214170754Sdelphij			return KTYPE_KANA;
215170754Sdelphij		}
216170754Sdelphij		if ((c >= 0x40) && (c <= 0xfc) && (c != 0x7f)) {
217170754Sdelphij			/* SJIS */
218170754Sdelphij			default_kanji = SJIS;
219170754Sdelphij			return KTYPE_SJIS;
220170754Sdelphij		}
221170754Sdelphij		break;
222170754Sdelphij	case KTYPE_SUJIS:
223170754Sdelphij		if ((c >= 0x40) && (c <= 0xa0) && (c != 0x7f)) {
224170754Sdelphij			/* SJIS */
225170754Sdelphij			default_kanji = SJIS;
226170754Sdelphij			return KTYPE_SJIS;
227170754Sdelphij		}
228170754Sdelphij		if ((c == 0xfd) || (c == 0xfe)) {
229170754Sdelphij			/* UJIS */
230170754Sdelphij			default_kanji = UJIS;
231170754Sdelphij			return KTYPE_UJIS;
232170754Sdelphij		}
233170754Sdelphij		if ((c >= 0xa1) && (c <= 0xfc)) {
234170754Sdelphij			if (default_kanji == SJIS)
235170754Sdelphij				return KTYPE_SJIS;
236170754Sdelphij			if (default_kanji == UJIS)
237170754Sdelphij				return KTYPE_UJIS;
238170754Sdelphij		}
239170754Sdelphij		break;
240170754Sdelphij	}
241170754Sdelphij
242170754Sdelphij	return KTYPE_ASCII;
243170754Sdelphij}
244170754Sdelphij
245170754Sdelphij/*
246170754Sdelphij * JIS X0208-83 keisen conversion table
247170754Sdelphij */
248170754Sdelphijstatic u_short keiConv[32] = {
249170754Sdelphij	0x240c, 0x260c, 0x300c, 0x340c, 0x3c0c, 0x380c, 0x400c, 0x500c,
250170754Sdelphij	0x480c, 0x580c, 0x600c, 0x250c, 0x270c, 0x330c, 0x370c, 0x3f0c,
251170754Sdelphij	0x3b0c, 0x470c, 0x570c, 0x4f0c, 0x5f0c, 0x6f0c, 0x440c, 0x530c,
252170754Sdelphij	0x4c0c, 0x5b0c, 0x630c, 0x410c, 0x540c, 0x490c, 0x5c0c, 0x660c
253170754Sdelphij};
254170754Sdelphij
255170754Sdelphijstatic u_short
256170754Sdelphijkanji_convert(u_char mode, u_char h, u_char l)
257170754Sdelphij{
258170754Sdelphij	u_short tmp, high, low, c;
259170754Sdelphij
260170754Sdelphij	high = (u_short) h;
261170754Sdelphij	low  = (u_short) l;
262170754Sdelphij
263170754Sdelphij	switch (mode) {
264170754Sdelphij	case KTYPE_SJIS: /* SHIFT JIS */
265170754Sdelphij		if (low >= 0xe0) {
266170754Sdelphij			low -= 0x40;
267170754Sdelphij		}
268170754Sdelphij		low = (low - 0x81) * 2 + 0x21;
269170754Sdelphij		if (high > 0x7f) {
270170754Sdelphij			high--;
271170754Sdelphij		}
272170754Sdelphij		if (high > 0x9d) {
273170754Sdelphij			low++;
274170754Sdelphij			high -= 0x9e - 0x21;
275170754Sdelphij		} else {
276170754Sdelphij			high -= 0x40 - 0x21;
277170754Sdelphij		}
278170754Sdelphij		high &= 0x7F;
279170754Sdelphij		low  &= 0x7F;
280170754Sdelphij		tmp = ((high << 8) | low) - 0x20;
281170754Sdelphij		break;
282170754Sdelphij	case KTYPE_7JIS: /* JIS */
283170754Sdelphij	case KTYPE_UJIS: /* UJIS */
284170754Sdelphij		high &= 0x7F;
285170754Sdelphij		low &= 0x7F;
286170754Sdelphij		tmp = ((high << 8) | low) - 0x20;
287170754Sdelphij		break;
288170754Sdelphij	default:
289170754Sdelphij		tmp = 0;
290170754Sdelphij		break;
291170754Sdelphij	}
292170754Sdelphij
293170754Sdelphij	/* keisen */
294170754Sdelphij	c = ((tmp & 0xff) << 8) | (tmp >> 8);
295170754Sdelphij	/* 0x2821 .. 0x2840 */
296170754Sdelphij	if (0x0821 <= c && c <= 0x0840)
297170754Sdelphij		tmp = keiConv[c - 0x0821];
298170754Sdelphij
299170754Sdelphij	return (tmp);
300170754Sdelphij}
301170754Sdelphij#endif /* KANJI */
302170754Sdelphij
303170754Sdelphijstatic int
304170754Sdelphijscterm_init(scr_stat *scp, void **softc, int code)
305170754Sdelphij{
306170754Sdelphij	term_stat *tcp;
307170754Sdelphij
308170754Sdelphij	if (*softc == NULL) {
309170754Sdelphij		if (reserved_term_stat.flags & SCTERM_BUSY)
310170754Sdelphij			return EINVAL;
311170754Sdelphij		*softc = &reserved_term_stat;
312170754Sdelphij	}
313170754Sdelphij	tcp = *softc;
314170754Sdelphij
315170754Sdelphij	switch (code) {
316170754Sdelphij	case SC_TE_COLD_INIT:
317170754Sdelphij		bzero(tcp, sizeof(*tcp));
318170754Sdelphij		tcp->flags = SCTERM_BUSY;
319170754Sdelphij		tcp->esc = 0;
320170754Sdelphij		tcp->saved_xpos = -1;
321170754Sdelphij		tcp->saved_ypos = -1;
322170754Sdelphij#ifdef KANJI
323170754Sdelphij		tcp->kanji_1st_char = 0;
324170754Sdelphij		tcp->kanji_type = KTYPE_ASCII;
325170754Sdelphij#endif
326170754Sdelphij		tcp->attr_mask = NORMAL_ATTR;
327170754Sdelphij		/* XXX */
328170754Sdelphij		tcp->dflt_std_color.fg = SC_NORM_ATTR & 0x0f;
329170754Sdelphij		tcp->dflt_std_color.bg = (SC_NORM_ATTR >> 4) & 0x0f;
330170754Sdelphij		tcp->dflt_rev_color.fg = SC_NORM_REV_ATTR & 0x0f;
331170754Sdelphij		tcp->dflt_rev_color.bg = (SC_NORM_REV_ATTR >> 4) & 0x0f;
332170754Sdelphij		tcp->std_color = tcp->dflt_std_color;
333170754Sdelphij		tcp->rev_color = tcp->dflt_rev_color;
334170754Sdelphij		tcp->cur_color = tcp->std_color;
335170754Sdelphij		tcp->cur_attr = mask2attr(tcp);
336170754Sdelphij		++sc_term_sc.te_refcount;
337170754Sdelphij		break;
338170754Sdelphij
339170754Sdelphij	case SC_TE_WARM_INIT:
340170754Sdelphij		tcp->esc = 0;
341170754Sdelphij		tcp->saved_xpos = -1;
342170754Sdelphij		tcp->saved_ypos = -1;
343170754Sdelphij#if 0
344170754Sdelphij		tcp->std_color = tcp->dflt_std_color;
345170754Sdelphij		tcp->rev_color = tcp->dflt_rev_color;
346170754Sdelphij#endif
347170754Sdelphij		tcp->cur_color = tcp->std_color;
348170754Sdelphij		tcp->cur_attr = mask2attr(tcp);
349170754Sdelphij		break;
350170754Sdelphij	}
351170754Sdelphij
352170754Sdelphij	return 0;
353170754Sdelphij}
354170754Sdelphij
355170754Sdelphijstatic int
356170754Sdelphijscterm_term(scr_stat *scp, void **softc)
357170754Sdelphij{
358170754Sdelphij	if (*softc == &reserved_term_stat) {
359170754Sdelphij		*softc = NULL;
360170754Sdelphij		bzero(&reserved_term_stat, sizeof(reserved_term_stat));
361170754Sdelphij	}
362170754Sdelphij	--sc_term_sc.te_refcount;
363170754Sdelphij	return 0;
364170754Sdelphij}
365170754Sdelphij
366170754Sdelphijstatic void
367170754Sdelphijscterm_scan_esc(scr_stat *scp, term_stat *tcp, u_char c)
368170754Sdelphij{
369170754Sdelphij	static u_char ansi_col[16] = {
370170754Sdelphij		FG_BLACK,     FG_RED,          FG_GREEN,      FG_BROWN,
371170754Sdelphij		FG_BLUE,      FG_MAGENTA,      FG_CYAN,       FG_LIGHTGREY,
372170754Sdelphij		FG_DARKGREY,  FG_LIGHTRED,     FG_LIGHTGREEN, FG_YELLOW,
373170754Sdelphij		FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN,  FG_WHITE
374170754Sdelphij	};
375170754Sdelphij	static int cattrs[] = {
376170754Sdelphij		0,					/* block */
377170754Sdelphij		CONS_BLINK_CURSOR,			/* blinking block */
378170754Sdelphij		CONS_CHAR_CURSOR,			/* underline */
379170754Sdelphij		CONS_CHAR_CURSOR | CONS_BLINK_CURSOR,	/* blinking underline */
380170754Sdelphij		CONS_RESET_CURSOR,			/* reset to default */
381170754Sdelphij		CONS_HIDDEN_CURSOR,			/* hide cursor */
382170754Sdelphij	};
383170754Sdelphij	static int tcattrs[] = {
384170754Sdelphij		CONS_RESET_CURSOR | CONS_LOCAL_CURSOR,	/* normal */
385170754Sdelphij		CONS_HIDDEN_CURSOR | CONS_LOCAL_CURSOR,	/* invisible */
386170754Sdelphij		CONS_BLINK_CURSOR | CONS_LOCAL_CURSOR,	/* very visible */
387170754Sdelphij	};
388170754Sdelphij	sc_softc_t *sc;
389170754Sdelphij	int v0, v1, v2;
390170754Sdelphij	int i, n;
391170754Sdelphij
392170754Sdelphij	i = n = 0;
393170754Sdelphij	sc = scp->sc;
394170754Sdelphij	if (tcp->esc == 1) {	/* seen ESC */
395170754Sdelphij#ifdef KANJI
396170754Sdelphij		switch (tcp->kanji_type) {
397170754Sdelphij		case KTYPE_KANIN:	/* Kanji Invoke sequence */
398170754Sdelphij			switch (c) {
399170754Sdelphij			case 'B':
400170754Sdelphij			case '@':
401170754Sdelphij				tcp->kanji_type = KTYPE_7JIS;
402170754Sdelphij				tcp->esc = 0;
403170754Sdelphij				tcp->kanji_1st_char = 0;
404170754Sdelphij				return;
405170754Sdelphij			default:
406170754Sdelphij				tcp->kanji_type = KTYPE_ASCII;
407170754Sdelphij				tcp->esc = 0;
408170754Sdelphij				break;
409170754Sdelphij			}
410170754Sdelphij			break;
411170754Sdelphij		case KTYPE_ASCIN:	/* Ascii Invoke sequence */
412170754Sdelphij			switch (c) {
413170754Sdelphij			case 'J':
414170754Sdelphij			case 'B':
415170754Sdelphij			case 'H':
416170754Sdelphij				tcp->kanji_type = KTYPE_ASCII;
417170754Sdelphij				tcp->esc = 0;
418170754Sdelphij				tcp->kanji_1st_char = 0;
419170754Sdelphij				return;
420170754Sdelphij			case 'I':
421170754Sdelphij				tcp->kanji_type = KTYPE_JKANA;
422170754Sdelphij				tcp->esc = 0;
423170754Sdelphij				tcp->kanji_1st_char = 0;
424170754Sdelphij				return;
425170754Sdelphij			default:
426170754Sdelphij				tcp->kanji_type = KTYPE_ASCII;
427170754Sdelphij				tcp->esc = 0;
428170754Sdelphij				break;
429170754Sdelphij			}
430170754Sdelphij			break;
431170754Sdelphij		default:
432170754Sdelphij			break;
433170754Sdelphij		}
434170754Sdelphij#endif
435170754Sdelphij		switch (c) {
436170754Sdelphij
437170754Sdelphij		case '7':	/* Save cursor position */
438170754Sdelphij			tcp->saved_xpos = scp->xpos;
439170754Sdelphij			tcp->saved_ypos = scp->ypos;
440170754Sdelphij			break;
441170754Sdelphij
442170754Sdelphij		case '8':	/* Restore saved cursor position */
443170754Sdelphij			if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
444170754Sdelphij				sc_move_cursor(scp, tcp->saved_xpos,
445170754Sdelphij					       tcp->saved_ypos);
446170754Sdelphij			break;
447170754Sdelphij
448170754Sdelphij		case '[':	/* Start ESC [ sequence */
449170754Sdelphij			tcp->esc = 2;
450170754Sdelphij			tcp->last_param = -1;
451170754Sdelphij			for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
452170754Sdelphij				tcp->param[i] = 1;
453170754Sdelphij			tcp->num_param = 0;
454170754Sdelphij			return;
455170754Sdelphij
456170754Sdelphij#ifdef KANJI
457170754Sdelphij		case '$':	/* Kanji Invoke sequence */
458170754Sdelphij			tcp->kanji_type = KTYPE_KANIN;
459170754Sdelphij			return;
460170754Sdelphij#endif
461170754Sdelphij
462170754Sdelphij		case 'M':	/* Move cursor up 1 line, scroll if at top */
463170754Sdelphij			sc_term_up_scroll(scp, 1, sc->scr_map[0x20],
464170754Sdelphij					  tcp->cur_attr, 0, 0);
465170754Sdelphij			break;
466170754Sdelphij#ifdef notyet
467170754Sdelphij		case 'Q':
468170754Sdelphij			tcp->esc = 4;
469170754Sdelphij			return;
470170754Sdelphij#endif
471170754Sdelphij		case 'c':       /* reset */
472170754Sdelphij			tcp->attr_mask = NORMAL_ATTR;
473170754Sdelphij			tcp->cur_color = tcp->std_color
474170754Sdelphij				       = tcp->dflt_std_color;
475170754Sdelphij			tcp->rev_color = tcp->dflt_rev_color;
476170754Sdelphij			tcp->cur_attr = mask2attr(tcp);
477170754Sdelphij			sc_change_cursor_shape(scp,
478170754Sdelphij			    CONS_RESET_CURSOR | CONS_LOCAL_CURSOR, -1, -1);
479170754Sdelphij			sc_clear_screen(scp);
480170754Sdelphij			break;
481170754Sdelphij
482170754Sdelphij		case '(':	/* iso-2022: designate 94 character set to G0 */
483170754Sdelphij#ifdef KANJI
484170754Sdelphij			tcp->kanji_type = KTYPE_ASCIN;
485170754Sdelphij#else
486170754Sdelphij			tcp->esc = 5;
487170754Sdelphij#endif
488170754Sdelphij			return;
489170754Sdelphij		}
490170754Sdelphij	} else if (tcp->esc == 2) {	/* seen ESC [ */
491170754Sdelphij		if (c >= '0' && c <= '9') {
492170754Sdelphij			if (tcp->num_param < MAX_ESC_PAR) {
493170754Sdelphij				if (tcp->last_param != tcp->num_param) {
494170754Sdelphij					tcp->last_param = tcp->num_param;
495170754Sdelphij					tcp->param[tcp->num_param] = 0;
496170754Sdelphij				} else {
497170754Sdelphij					tcp->param[tcp->num_param] *= 10;
498170754Sdelphij				}
499170754Sdelphij				tcp->param[tcp->num_param] += c - '0';
500170754Sdelphij				return;
501170754Sdelphij			}
502170754Sdelphij		}
503170754Sdelphij		tcp->num_param = tcp->last_param + 1;
504170754Sdelphij		switch (c) {
505170754Sdelphij
506170754Sdelphij		case ';':
507170754Sdelphij			if (tcp->num_param < MAX_ESC_PAR)
508170754Sdelphij				return;
509170754Sdelphij			break;
510170754Sdelphij
511170754Sdelphij		case '=':
512170754Sdelphij			tcp->esc = 3;
513170754Sdelphij			tcp->last_param = -1;
514170754Sdelphij			for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
515170754Sdelphij				tcp->param[i] = 1;
516170754Sdelphij			tcp->num_param = 0;
517170754Sdelphij			return;
518170754Sdelphij
519170754Sdelphij		case 'A':	/* up n rows */
520170754Sdelphij			sc_term_up(scp, tcp->param[0], 0);
521170754Sdelphij			break;
522170754Sdelphij
523170754Sdelphij		case 'B':	/* down n rows */
524170754Sdelphij			sc_term_down(scp, tcp->param[0], 0);
525170754Sdelphij			break;
526170754Sdelphij
527170754Sdelphij		case 'C':	/* right n columns */
528170754Sdelphij			sc_term_right(scp, tcp->param[0]);
529170754Sdelphij			break;
530170754Sdelphij
531170754Sdelphij		case 'D':	/* left n columns */
532170754Sdelphij			sc_term_left(scp, tcp->param[0]);
533170754Sdelphij			break;
534170754Sdelphij
535170754Sdelphij		case 'E':	/* cursor to start of line n lines down */
536170754Sdelphij			n = tcp->param[0];
537170754Sdelphij			if (n < 1)
538170754Sdelphij				n = 1;
539170754Sdelphij			sc_move_cursor(scp, 0, scp->ypos + n);
540170754Sdelphij			break;
541170754Sdelphij
542170754Sdelphij		case 'F':	/* cursor to start of line n lines up */
543170754Sdelphij			n = tcp->param[0];
544170754Sdelphij			if (n < 1)
545170754Sdelphij				n = 1;
546170754Sdelphij			sc_move_cursor(scp, 0, scp->ypos - n);
547170754Sdelphij			break;
548170754Sdelphij
549170754Sdelphij		case 'f':	/* Cursor move */
550170754Sdelphij		case 'H':
551170754Sdelphij			if (tcp->num_param == 0)
552170754Sdelphij				sc_move_cursor(scp, 0, 0);
553170754Sdelphij			else if (tcp->num_param == 2)
554170754Sdelphij				sc_move_cursor(scp, tcp->param[1] - 1,
555170754Sdelphij					       tcp->param[0] - 1);
556170754Sdelphij			break;
557170754Sdelphij
558170754Sdelphij		case 'J':	/* Clear all or part of display */
559170754Sdelphij			if (tcp->num_param == 0)
560170754Sdelphij				n = 0;
561170754Sdelphij			else
562170754Sdelphij				n = tcp->param[0];
563170754Sdelphij			sc_term_clr_eos(scp, n, sc->scr_map[0x20],
564170754Sdelphij					tcp->cur_attr);
565170754Sdelphij			break;
566170754Sdelphij
567170754Sdelphij		case 'K':	/* Clear all or part of line */
568170754Sdelphij			if (tcp->num_param == 0)
569170754Sdelphij				n = 0;
570170754Sdelphij			else
571170754Sdelphij				n = tcp->param[0];
572170754Sdelphij			sc_term_clr_eol(scp, n, sc->scr_map[0x20],
573170754Sdelphij					tcp->cur_attr);
574170754Sdelphij			break;
575170754Sdelphij
576170754Sdelphij		case 'L':	/* Insert n lines */
577170754Sdelphij			sc_term_ins_line(scp, scp->ypos, tcp->param[0],
578170754Sdelphij					 sc->scr_map[0x20], tcp->cur_attr, 0);
579170754Sdelphij			break;
580170754Sdelphij
581170754Sdelphij		case 'M':	/* Delete n lines */
582170754Sdelphij			sc_term_del_line(scp, scp->ypos, tcp->param[0],
583170754Sdelphij					 sc->scr_map[0x20], tcp->cur_attr, 0);
584170754Sdelphij			break;
585170754Sdelphij
586170754Sdelphij		case 'P':	/* Delete n chars */
587170754Sdelphij			sc_term_del_char(scp, tcp->param[0],
588170754Sdelphij					 sc->scr_map[0x20], tcp->cur_attr);
589170754Sdelphij			break;
590170754Sdelphij
591170754Sdelphij		case '@':	/* Insert n chars */
592170754Sdelphij			sc_term_ins_char(scp, tcp->param[0],
593170754Sdelphij					 sc->scr_map[0x20], tcp->cur_attr);
594170754Sdelphij			break;
595170754Sdelphij
596170754Sdelphij		case 'S':	/* scroll up n lines */
597170754Sdelphij			sc_term_del_line(scp, 0, tcp->param[0],
598170754Sdelphij					 sc->scr_map[0x20], tcp->cur_attr, 0);
599170754Sdelphij			break;
600170754Sdelphij
601170754Sdelphij		case 'T':	/* scroll down n lines */
602170754Sdelphij			sc_term_ins_line(scp, 0, tcp->param[0],
603170754Sdelphij					 sc->scr_map[0x20], tcp->cur_attr, 0);
604170754Sdelphij			break;
605170754Sdelphij
606170754Sdelphij		case 'X':	/* erase n characters in line */
607170754Sdelphij			n = tcp->param[0];
608170754Sdelphij			if (n < 1)
609170754Sdelphij				n = 1;
610170754Sdelphij			if (n > scp->xsize - scp->xpos)
611170754Sdelphij				n = scp->xsize - scp->xpos;
612170754Sdelphij			sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
613170754Sdelphij				     sc->scr_map[0x20], tcp->cur_attr);
614170754Sdelphij			mark_for_update(scp, scp->cursor_pos);
615170754Sdelphij			mark_for_update(scp, scp->cursor_pos + n - 1);
616170754Sdelphij			break;
617170754Sdelphij
618170754Sdelphij		case 'Z':	/* move n tabs backwards */
619170754Sdelphij			sc_term_backtab(scp, tcp->param[0]);
620170754Sdelphij			break;
621170754Sdelphij
622170754Sdelphij		case '`':	/* move cursor to column n */
623170754Sdelphij			sc_term_col(scp, tcp->param[0]);
624170754Sdelphij			break;
625170754Sdelphij
626170754Sdelphij		case 'a':	/* move cursor n columns to the right */
627170754Sdelphij			sc_term_right(scp, tcp->param[0]);
628170754Sdelphij			break;
629170754Sdelphij
630170754Sdelphij		case 'd':	/* move cursor to row n */
631170754Sdelphij			sc_term_row(scp, tcp->param[0]);
632170754Sdelphij			break;
633170754Sdelphij
634170754Sdelphij		case 'e':	/* move cursor n rows down */
635170754Sdelphij			sc_term_down(scp, tcp->param[0], 0);
636170754Sdelphij			break;
637170754Sdelphij
638170754Sdelphij		case 'm':	/* change attribute */
639170754Sdelphij			if (tcp->num_param == 0) {
640170754Sdelphij				tcp->attr_mask = NORMAL_ATTR;
641170754Sdelphij				tcp->cur_color = tcp->std_color;
642170754Sdelphij				tcp->cur_attr = mask2attr(tcp);
643170754Sdelphij				break;
644170754Sdelphij			}
645170754Sdelphij			for (i = 0; i < tcp->num_param; i++) {
646170754Sdelphij				switch (n = tcp->param[i]) {
647170754Sdelphij				case 0:	/* back to normal */
648170754Sdelphij					tcp->attr_mask = NORMAL_ATTR;
649170754Sdelphij					tcp->cur_color = tcp->std_color;
650170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
651170754Sdelphij					break;
652170754Sdelphij				case 1:	/* bold */
653170754Sdelphij					tcp->attr_mask |= BOLD_ATTR;
654170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
655170754Sdelphij					break;
656170754Sdelphij				case 4:	/* underline */
657170754Sdelphij					tcp->attr_mask |= UNDERLINE_ATTR;
658170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
659170754Sdelphij					break;
660170754Sdelphij				case 5:	/* blink */
661170754Sdelphij					tcp->attr_mask |= BLINK_ATTR;
662170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
663170754Sdelphij					break;
664170754Sdelphij				case 7: /* reverse */
665170754Sdelphij					tcp->attr_mask |= REVERSE_ATTR;
666170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
667170754Sdelphij					break;
668170754Sdelphij				case 22: /* remove bold (or dim) */
669170754Sdelphij					tcp->attr_mask &= ~BOLD_ATTR;
670170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
671170754Sdelphij					break;
672170754Sdelphij				case 24: /* remove underline */
673170754Sdelphij					tcp->attr_mask &= ~UNDERLINE_ATTR;
674170754Sdelphij					tcp->cur_attr = mask2attr(tcp);
675170754Sdelphij					break;
676170754Sdelphij				case 25: /* remove blink */
677170754Sdelphij					tcp->attr_mask &= ~BLINK_ATTR;
678					tcp->cur_attr = mask2attr(tcp);
679					break;
680				case 27: /* remove reverse */
681					tcp->attr_mask &= ~REVERSE_ATTR;
682					tcp->cur_attr = mask2attr(tcp);
683					break;
684				case 30: case 31: /* set ansi fg color */
685				case 32: case 33: case 34:
686				case 35: case 36: case 37:
687					tcp->attr_mask |= FG_CHANGED;
688					tcp->cur_color.fg = ansi_col[n - 30];
689					tcp->cur_attr = mask2attr(tcp);
690					break;
691				case 39: /* restore fg color back to normal */
692					tcp->attr_mask &= ~(FG_CHANGED|BOLD_ATTR);
693					tcp->cur_color.fg = tcp->std_color.fg;
694					tcp->cur_attr = mask2attr(tcp);
695					break;
696				case 40: case 41: /* set ansi bg color */
697				case 42: case 43: case 44:
698				case 45: case 46: case 47:
699					tcp->attr_mask |= BG_CHANGED;
700					tcp->cur_color.bg = ansi_col[n - 40];
701					tcp->cur_attr = mask2attr(tcp);
702					break;
703				case 49: /* restore bg color back to normal */
704					tcp->attr_mask &= ~BG_CHANGED;
705					tcp->cur_color.bg = tcp->std_color.bg;
706					tcp->cur_attr = mask2attr(tcp);
707					break;
708				}
709			}
710			break;
711
712		case 's':	/* Save cursor position */
713			tcp->saved_xpos = scp->xpos;
714			tcp->saved_ypos = scp->ypos;
715			break;
716
717		case 'u':	/* Restore saved cursor position */
718			if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
719				sc_move_cursor(scp, tcp->saved_xpos,
720					       tcp->saved_ypos);
721			break;
722
723		case 'x':
724			if (tcp->num_param == 0)
725				n = 0;
726			else
727				n = tcp->param[0];
728			switch (n) {
729			case 0: /* reset colors and attributes back to normal */
730				tcp->attr_mask = NORMAL_ATTR;
731				tcp->cur_color = tcp->std_color
732					       = tcp->dflt_std_color;
733				tcp->rev_color = tcp->dflt_rev_color;
734				tcp->cur_attr = mask2attr(tcp);
735				break;
736			case 1:	/* set ansi background */
737				tcp->attr_mask &= ~BG_CHANGED;
738				tcp->cur_color.bg = tcp->std_color.bg
739						  = ansi_col[tcp->param[1] & 0x0f];
740				tcp->cur_attr = mask2attr(tcp);
741				break;
742			case 2:	/* set ansi foreground */
743				tcp->attr_mask &= ~FG_CHANGED;
744				tcp->cur_color.fg = tcp->std_color.fg
745						  = ansi_col[tcp->param[1] & 0x0f];
746				tcp->cur_attr = mask2attr(tcp);
747				break;
748			case 3: /* set adapter attribute directly */
749				tcp->attr_mask &= ~(FG_CHANGED | BG_CHANGED);
750				tcp->cur_color.fg = tcp->std_color.fg
751						  = tcp->param[1] & 0x0f;
752				tcp->cur_color.bg = tcp->std_color.bg
753						  = (tcp->param[1] >> 4) & 0x0f;
754				tcp->cur_attr = mask2attr(tcp);
755				break;
756			case 5: /* set ansi reverse background */
757				tcp->rev_color.bg = ansi_col[tcp->param[1] & 0x0f];
758				tcp->cur_attr = mask2attr(tcp);
759				break;
760			case 6: /* set ansi reverse foreground */
761				tcp->rev_color.fg = ansi_col[tcp->param[1] & 0x0f];
762				tcp->cur_attr = mask2attr(tcp);
763				break;
764			case 7: /* set adapter reverse attribute directly */
765				tcp->rev_color.fg = tcp->param[1] & 0x0f;
766				tcp->rev_color.bg = (tcp->param[1] >> 4) & 0x0f;
767				tcp->cur_attr = mask2attr(tcp);
768				break;
769			}
770			break;
771
772		case 'z':	/* switch to (virtual) console n */
773			if (tcp->num_param == 1)
774				sc_switch_scr(sc, tcp->param[0]);
775			break;
776		}
777	} else if (tcp->esc == 3) {	/* seen ESC [0-9]+ = */
778		if (c >= '0' && c <= '9') {
779			if (tcp->num_param < MAX_ESC_PAR) {
780				if (tcp->last_param != tcp->num_param) {
781					tcp->last_param = tcp->num_param;
782					tcp->param[tcp->num_param] = 0;
783				} else {
784					tcp->param[tcp->num_param] *= 10;
785				}
786				tcp->param[tcp->num_param] += c - '0';
787				return;
788			}
789		}
790		tcp->num_param = tcp->last_param + 1;
791		switch (c) {
792
793		case ';':
794			if (tcp->num_param < MAX_ESC_PAR)
795				return;
796			break;
797
798		case 'A':   /* set display border color */
799			if (tcp->num_param == 1) {
800				scp->border=tcp->param[0] & 0xff;
801				if (scp == sc->cur_scp)
802					sc_set_border(scp, scp->border);
803			}
804			break;
805
806		case 'B':   /* set bell pitch and duration */
807			if (tcp->num_param == 2) {
808				scp->bell_pitch = tcp->param[0];
809				scp->bell_duration =
810				    (tcp->param[1] * hz + 99) / 100;
811			}
812			break;
813
814		case 'C':   /* set global/parmanent cursor type & shape */
815			i = spltty();
816			n = tcp->num_param;
817			v0 = tcp->param[0];
818			v1 = tcp->param[1];
819			v2 = tcp->param[2];
820			switch (n) {
821			case 1:	/* flags only */
822				if (v0 < nitems(cattrs))
823					v0 = cattrs[v0];
824				else	/* backward compatibility */
825					v0 = cattrs[v0 & 0x3];
826				sc_change_cursor_shape(scp, v0, -1, -1);
827				break;
828			case 2:
829				v2 = 0;
830				v0 &= 0x1f;	/* backward compatibility */
831				v1 &= 0x1f;
832				/* FALL THROUGH */
833			case 3:	/* base and height */
834				if (v2 == 0)	/* count from top */
835					sc_change_cursor_shape(scp, -1,
836					    scp->font_size - v1 - 1,
837					    v1 - v0 + 1);
838				else if (v2 == 1) /* count from bottom */
839					sc_change_cursor_shape(scp, -1,
840					    v0, v1 - v0 + 1);
841				break;
842			}
843			splx(i);
844			break;
845
846		case 'F':   /* set adapter foreground */
847			if (tcp->num_param == 1) {
848				tcp->attr_mask &= ~FG_CHANGED;
849				tcp->cur_color.fg = tcp->std_color.fg
850						  = tcp->param[0] & 0x0f;
851				tcp->cur_attr = mask2attr(tcp);
852			}
853			break;
854
855		case 'G':   /* set adapter background */
856			if (tcp->num_param == 1) {
857				tcp->attr_mask &= ~BG_CHANGED;
858				tcp->cur_color.bg = tcp->std_color.bg
859						  = tcp->param[0] & 0x0f;
860				tcp->cur_attr = mask2attr(tcp);
861			}
862			break;
863
864		case 'H':   /* set adapter reverse foreground */
865			if (tcp->num_param == 1) {
866				tcp->rev_color.fg = tcp->param[0] & 0x0f;
867				tcp->cur_attr = mask2attr(tcp);
868			}
869			break;
870
871		case 'I':   /* set adapter reverse background */
872			if (tcp->num_param == 1) {
873				tcp->rev_color.bg = tcp->param[0] & 0x0f;
874				tcp->cur_attr = mask2attr(tcp);
875			}
876			break;
877
878		case 'S':   /* set local/temporary cursor type & shape */
879			i = spltty();
880			n = tcp->num_param;
881			v0 = tcp->param[0];
882			switch (n) {
883			case 0:
884				v0 = 0;
885				/* FALL THROUGH */
886			case 1:
887				if (v0 < nitems(tcattrs))
888					sc_change_cursor_shape(scp,
889					    tcattrs[v0], -1, -1);
890				break;
891			}
892			splx(i);
893			break;
894		}
895#ifdef notyet
896	} else if (tcp->esc == 4) {	/* seen ESC Q */
897		/* to be filled */
898#endif
899	} else if (tcp->esc == 5) {	/* seen ESC ( */
900		switch (c) {
901		case 'B':   /* iso-2022: desginate ASCII into G0 */
902			break;
903		/* other items to be filled */
904		default:
905			break;
906		}
907	}
908	tcp->esc = 0;
909}
910
911static void
912scterm_puts(scr_stat *scp, u_char *buf, int len, int kernel)
913{
914	term_stat *tcp;
915	u_char *ptr;
916#ifdef KANJI
917	u_short kanji_code;
918#endif
919	color_t backup;
920
921	tcp = scp->ts;
922	ptr = buf;
923outloop:
924	scp->sc->write_in_progress++;
925	backup = tcp->cur_color;
926	if (kernel) {
927		tcp->cur_color.fg = SC_KERNEL_CONS_ATTR & 0x0f;
928		tcp->cur_color.bg = (SC_KERNEL_CONS_ATTR >> 4) & 0x0f;
929	}
930
931	if (tcp->esc) {
932		scterm_scan_esc(scp, tcp, *ptr++);
933		len--;
934	} else if (PRINTABLE(*ptr)) {     /* Print only printables */
935		vm_offset_t p;
936		u_char *map;
937		int attr;
938		int i;
939		int cnt;
940#ifdef KANJI
941		u_char c;
942#endif
943
944		p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
945		map = scp->sc->scr_map;
946		attr = tcp->cur_attr;
947
948#ifdef KANJI
949		c = *ptr;
950		if (tcp->kanji_1st_char == 0) {
951		    tcp->kanji_type = iskanji1(tcp->kanji_type, c);
952		    if (!IS_KTYPE_ASCII_or_HANKAKU(tcp->kanji_type)) {
953			/* not Ascii & not HANKAKU */
954			tcp->kanji_1st_char = c;
955			goto kanji_end;
956		    } else if (tcp->kanji_type == KTYPE_ASCII) {
957			cnt = imin(len, scp->xsize - scp->xpos);
958			i = cnt;
959			do {
960			    p = sc_vtb_putchar(&scp->vtb, p, map[c], attr);
961			    c = *++ptr;
962			    --i;
963			} while (i > 0 && PRINTABLE(c) &&
964				 iskanji1(tcp->kanji_type, c) == KTYPE_ASCII);
965
966			len -= cnt - i;
967			mark_for_update(scp, scp->cursor_pos);
968			scp->cursor_pos += cnt - i;
969			mark_for_update(scp, scp->cursor_pos - 1);
970			scp->xpos += cnt - i;
971			KTYPE_MASK_CTRL(tcp->kanji_type);
972			goto ascii_end;
973		    }
974		} else {
975		    if ((tcp->kanji_type =
976			 iskanji2(tcp->kanji_type, c)) & 0xee) {
977			/* print kanji on TEXT VRAM */
978			kanji_code = kanji_convert(tcp->kanji_type, c,
979						   tcp->kanji_1st_char);
980			mark_for_update(scp, scp->cursor_pos);
981			for (i = 0; i < 2; i++) {
982			    /* *cursor_pos = (kanji_code | (i*0x80)); */
983			    p = sc_vtb_putchar(&scp->vtb, p,
984			       kanji_code | ((i == 0) ? 0x00 : 0x80), attr);
985			    ++scp->cursor_pos;
986			    if (++scp->xpos >= scp->xsize) {
987				scp->xpos = 0;
988				scp->ypos++;
989			    }
990			}
991			mark_for_update(scp, scp->cursor_pos - 1);
992			KTYPE_MASK_CTRL(tcp->kanji_type);
993			tcp->kanji_1st_char = 0;
994			goto kanji_end;
995		    } else {
996			tcp->kanji_1st_char = 0;
997		    }
998		}
999		if (IS_KTYPE_KANA(tcp->kanji_type))
1000		    c |= 0x80;
1001		KTYPE_MASK_CTRL(tcp->kanji_type);
1002		sc_vtb_putchar(&scp->vtb, p, map[c], attr);
1003		mark_for_update(scp, scp->cursor_pos);
1004		mark_for_update(scp, scp->cursor_pos);
1005		++scp->cursor_pos;
1006		++scp->xpos;
1007kanji_end:
1008		++ptr;
1009		--len;
1010ascii_end:
1011#else /* !KANJI */
1012		cnt = imin(len, scp->xsize - scp->xpos);
1013		i = cnt;
1014		do {
1015		    /*
1016		     * gcc-2.6.3 generates poor (un)sign extension code.
1017		     * Casting the pointers in the following to volatile should
1018		     * have no effect, but in fact speeds up this inner loop
1019		     * from 26 to 18 cycles (+ cache misses) on i486's.
1020		     */
1021#define	UCVP(ucp)	((u_char volatile *)(ucp))
1022		    p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)],
1023				       attr);
1024		    ++ptr;
1025		    --i;
1026		} while (i > 0 && PRINTABLE(*ptr));
1027
1028		len -= cnt - i;
1029		mark_for_update(scp, scp->cursor_pos);
1030		scp->cursor_pos += cnt - i;
1031		mark_for_update(scp, scp->cursor_pos - 1);
1032		scp->xpos += cnt - i;
1033#endif /* !KANJI */
1034
1035		if (scp->xpos >= scp->xsize) {
1036			scp->xpos = 0;
1037			scp->ypos++;
1038		}
1039	} else {
1040		switch (*ptr) {
1041		case 0x07:
1042			sc_bell(scp, scp->bell_pitch, scp->bell_duration);
1043			break;
1044
1045		case 0x08:	/* non-destructive backspace */
1046			if (scp->cursor_pos > 0) {
1047				mark_for_update(scp, scp->cursor_pos);
1048				scp->cursor_pos--;
1049				mark_for_update(scp, scp->cursor_pos);
1050				if (scp->xpos > 0)
1051					scp->xpos--;
1052				else {
1053					scp->xpos += scp->xsize - 1;
1054					scp->ypos--;
1055				}
1056			}
1057			break;
1058
1059		case 0x09:	/* non-destructive tab */
1060			mark_for_update(scp, scp->cursor_pos);
1061			scp->cursor_pos += (8 - scp->xpos % 8u);
1062			scp->xpos += (8 - scp->xpos % 8u);
1063			if (scp->xpos >= scp->xsize) {
1064				scp->xpos = 0;
1065				scp->ypos++;
1066				scp->cursor_pos = scp->xsize * scp->ypos;
1067			}
1068			mark_for_update(scp, scp->cursor_pos);
1069			break;
1070
1071		case 0x0a:	/* newline, same pos */
1072			mark_for_update(scp, scp->cursor_pos);
1073			scp->cursor_pos += scp->xsize;
1074			mark_for_update(scp, scp->cursor_pos);
1075			scp->ypos++;
1076			break;
1077
1078		case 0x0c:	/* form feed, clears screen */
1079			sc_clear_screen(scp);
1080			break;
1081
1082		case 0x0d:	/* return, return to pos 0 */
1083			mark_for_update(scp, scp->cursor_pos);
1084			scp->cursor_pos -= scp->xpos;
1085			mark_for_update(scp, scp->cursor_pos);
1086			scp->xpos = 0;
1087			break;
1088
1089		case 0x0e:	/* ^N */
1090			tcp->kanji_type = KTYPE_JKANA;
1091			tcp->esc = 0;
1092			tcp->kanji_1st_char = 0;
1093			break;
1094
1095		case 0x0f:	/* ^O */
1096			tcp->kanji_type = KTYPE_ASCII;
1097			tcp->esc = 0;
1098			tcp->kanji_1st_char = 0;
1099			break;
1100
1101		case 0x1b:	/* start escape sequence */
1102			tcp->esc = 1;
1103			tcp->num_param = 0;
1104			break;
1105		}
1106		ptr++;
1107		len--;
1108	}
1109
1110	sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
1111
1112	if (kernel)
1113		tcp->cur_color = backup;
1114	scp->sc->write_in_progress--;
1115	if (len)
1116		goto outloop;
1117}
1118
1119static int
1120scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
1121	     struct thread *td)
1122{
1123	term_stat *tcp = scp->ts;
1124	vid_info_t *vi;
1125
1126	switch (cmd) {
1127	case GIO_ATTR:      	/* get current attributes */
1128		/* FIXME: */
1129		*(int*)data = (tcp->cur_attr >> 8) & 0xff;
1130		return 0;
1131	case CONS_GETINFO:  	/* get current (virtual) console info */
1132		vi = (vid_info_t *)data;
1133		if (vi->size != sizeof(struct vid_info))
1134			return EINVAL;
1135		vi->mv_norm.fore = tcp->std_color.fg;
1136		vi->mv_norm.back = tcp->std_color.bg;
1137		vi->mv_rev.fore = tcp->rev_color.fg;
1138		vi->mv_rev.back = tcp->rev_color.bg;
1139		/*
1140		 * The other fields are filled by the upper routine. XXX
1141		 */
1142		return ENOIOCTL;
1143	}
1144	return ENOIOCTL;
1145}
1146
1147static int
1148scterm_reset(scr_stat *scp, int code)
1149{
1150	/* FIXME */
1151	return 0;
1152}
1153
1154static void
1155scterm_default_attr(scr_stat *scp, int color, int rev_color)
1156{
1157	term_stat *tcp = scp->ts;
1158
1159	tcp->dflt_std_color.fg = color & 0x0f;
1160	tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
1161	tcp->dflt_rev_color.fg = rev_color & 0x0f;
1162	tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
1163	tcp->std_color = tcp->dflt_std_color;
1164	tcp->rev_color = tcp->dflt_rev_color;
1165	tcp->cur_color = tcp->std_color;
1166	tcp->cur_attr = mask2attr(tcp);
1167}
1168
1169static void
1170scterm_clear(scr_stat *scp)
1171{
1172	term_stat *tcp = scp->ts;
1173
1174	sc_move_cursor(scp, 0, 0);
1175	sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
1176	mark_all(scp);
1177}
1178
1179static void
1180scterm_notify(scr_stat *scp, int event)
1181{
1182	switch (event) {
1183	case SC_TE_NOTIFY_VTSWITCH_IN:
1184		break;
1185	case SC_TE_NOTIFY_VTSWITCH_OUT:
1186		break;
1187	}
1188}
1189
1190static int
1191scterm_input(scr_stat *scp, int c, struct tty *tp)
1192{
1193	return FALSE;
1194}
1195
1196static const char *
1197scterm_fkeystr(scr_stat *scp, int c)
1198{
1199
1200	return (NULL);
1201}
1202
1203/*
1204 * Calculate hardware attributes word using logical attributes mask and
1205 * hardware colors
1206 */
1207
1208/* FIXME */
1209static int
1210mask2attr(term_stat *tcp)
1211{
1212	int attr, mask = tcp->attr_mask;
1213
1214	if (mask & REVERSE_ATTR) {
1215		attr = ((mask & FG_CHANGED) ?
1216			tcp->cur_color.bg : tcp->rev_color.fg) |
1217			(((mask & BG_CHANGED) ?
1218			tcp->cur_color.fg : tcp->rev_color.bg) << 4);
1219	} else
1220		attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
1221
1222	/* XXX: underline mapping for Hercules adapter can be better */
1223	if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
1224		attr ^= 0x08;
1225	if (mask & BLINK_ATTR)
1226		attr ^= 0x80;
1227
1228	return (attr << 8);
1229}
1230