scterm-sck.c revision 61950
1/*-
2 * Copyright (c) 1999 FreeBSD(98) Porting Team.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer as
10 *    the first lines of this file unmodified.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/pc98/cbus/scterm-sck.c 61950 2000-06-22 10:03:28Z nyan $
27 */
28
29#include "opt_syscons.h"
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/consio.h>
35
36#include <machine/pc/display.h>
37
38#include <dev/syscons/syscons.h>
39#include <dev/syscons/sctermvar.h>
40
41#ifndef SC_DUMB_TERMINAL
42
43#define MAX_ESC_PAR	5
44
45#ifdef KANJI
46#define IS_KTYPE_ASCII_or_HANKAKU(A)	(!((A) & 0xee))
47#define IS_KTYPE_KANA(A)		((A) & 0x11)
48#define KTYPE_MASK_CTRL(A)		((A) &= 0xF0)
49#endif /* KANJI */
50
51/* attribute flags */
52typedef struct {
53	u_short		fg;			/* foreground color */
54	u_short		bg;			/* background color */
55} color_t;
56
57typedef struct {
58	int		flags;
59#define SCTERM_BUSY	(1 << 0)
60	int		esc;
61	int		num_param;
62	int		last_param;
63	int		param[MAX_ESC_PAR];
64	int		saved_xpos;
65	int		saved_ypos;
66
67#ifdef KANJI
68	u_char		kanji_1st_char;
69	u_char		kanji_type;
70#define KTYPE_ASCII	0			/* ASCII */
71#define KTYPE_KANA	1			/* HANKAKU */
72#define KTYPE_JKANA	0x10			/* JIS HANKAKU */
73#define KTYPE_7JIS	0x20			/* JIS */
74#define KTYPE_SJIS	2			/* Shift JIS */
75#define KTYPE_UJIS	4			/* UJIS */
76#define KTYPE_SUKANA	3			/* Shift JIS or UJIS HANKAKU */
77#define KTYPE_SUJIS	6			/* SHift JIS or UJIS */
78#define KTYPE_KANIN	0x80			/* Kanji Invoke sequence */
79#define KTYPE_ASCIN	0x40			/* ASCII Invoke sequence */
80#endif /* KANJI */
81
82	int		attr_mask;		/* current logical attr mask */
83#define NORMAL_ATTR	0x00
84#define BLINK_ATTR	0x01
85#define BOLD_ATTR	0x02
86#define UNDERLINE_ATTR	0x04
87#define REVERSE_ATTR	0x08
88#define FG_CHANGED	0x10
89#define BG_CHANGED	0x20
90	int		cur_attr;		/* current hardware attr word */
91	color_t		cur_color;		/* current hardware color */
92	color_t		std_color;		/* normal hardware color */
93	color_t		rev_color;		/* reverse hardware color */
94	color_t		dflt_std_color;		/* default normal color */
95	color_t		dflt_rev_color;		/* default reverse color */
96} term_stat;
97
98static sc_term_init_t	scterm_init;
99static sc_term_term_t	scterm_term;
100static sc_term_puts_t	scterm_puts;
101static sc_term_ioctl_t	scterm_ioctl;
102static sc_term_reset_t	scterm_reset;
103static sc_term_default_attr_t	scterm_default_attr;
104static sc_term_clear_t	scterm_clear;
105static sc_term_notify_t	scterm_notify;
106static sc_term_input_t	scterm_input;
107
108static sc_term_sw_t sc_term_sc = {
109	{ NULL, NULL },
110	"sck",					/* emulator name */
111	"syscons kanji terminal",		/* description */
112	"*",					/* matching renderer, any :-) */
113	sizeof(term_stat),			/* softc size */
114	0,
115	scterm_init,
116	scterm_term,
117	scterm_puts,
118	scterm_ioctl,
119	scterm_reset,
120	scterm_default_attr,
121	scterm_clear,
122	scterm_notify,
123	scterm_input,
124};
125
126SCTERM_MODULE(sc, sc_term_sc);
127
128static term_stat	reserved_term_stat;
129static int		default_kanji = UJIS;
130static void		scterm_scan_esc(scr_stat *scp, term_stat *tcp,
131					u_char c);
132static int		mask2attr(term_stat *tcp);
133static u_char		iskanji1(u_char mode, u_char c);
134static u_char		iskanji2(u_char mode, u_char c);
135static u_short		kanji_convert(u_char mode, u_char h, u_char l);
136
137static int
138scterm_init(scr_stat *scp, void **softc, int code)
139{
140	term_stat *tcp;
141
142	if (*softc == NULL) {
143		if (reserved_term_stat.flags & SCTERM_BUSY)
144			return EINVAL;
145		*softc = &reserved_term_stat;
146	}
147	tcp = *softc;
148
149	switch (code) {
150	case SC_TE_COLD_INIT:
151		bzero(tcp, sizeof(*tcp));
152		tcp->flags = SCTERM_BUSY;
153		tcp->esc = 0;
154		tcp->saved_xpos = -1;
155		tcp->saved_ypos = -1;
156
157#ifdef KANJI
158		tcp->kanji_1st_char = 0;
159		tcp->kanji_type = KTYPE_ASCII;
160#endif
161
162		tcp->attr_mask = NORMAL_ATTR;
163		/* XXX */
164		tcp->dflt_std_color.fg = SC_NORM_ATTR & 0x0f;
165		tcp->dflt_std_color.bg = (SC_NORM_ATTR >> 4) & 0x0f;
166		tcp->dflt_rev_color.fg = SC_NORM_REV_ATTR & 0x0f;
167		tcp->dflt_rev_color.bg = (SC_NORM_REV_ATTR >> 4) & 0x0f;
168		tcp->std_color = tcp->dflt_std_color;
169		tcp->rev_color = tcp->dflt_rev_color;
170		tcp->cur_color = tcp->std_color;
171		tcp->cur_attr = mask2attr(tcp);
172		++sc_term_sc.te_refcount;
173		break;
174
175	case SC_TE_WARM_INIT:
176		tcp->esc = 0;
177		tcp->saved_xpos = -1;
178		tcp->saved_ypos = -1;
179#if 0
180		tcp->std_color = tcp->dflt_std_color;
181		tcp->rev_color = tcp->dflt_rev_color;
182#endif
183		tcp->cur_color = tcp->std_color;
184		tcp->cur_attr = mask2attr(tcp);
185		break;
186	}
187
188	return 0;
189}
190
191static int
192scterm_term(scr_stat *scp, void **softc)
193{
194	if (*softc == &reserved_term_stat) {
195		*softc = NULL;
196		bzero(&reserved_term_stat, sizeof(reserved_term_stat));
197	}
198	--sc_term_sc.te_refcount;
199	return 0;
200}
201
202static void
203scterm_scan_esc(scr_stat *scp, term_stat *tcp, u_char c)
204{
205	static u_char ansi_col[16] = {
206		FG_BLACK,     FG_RED,          FG_GREEN,      FG_BROWN,
207		FG_BLUE,      FG_MAGENTA,      FG_CYAN,       FG_LIGHTGREY,
208		FG_DARKGREY,  FG_LIGHTRED,     FG_LIGHTGREEN, FG_YELLOW,
209		FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN,  FG_WHITE
210	};
211	sc_softc_t *sc;
212	int i, n;
213
214	i = n = 0;
215	sc = scp->sc;
216	if (tcp->esc == 1) {	/* seen ESC */
217#ifdef KANJI
218		switch (tcp->kanji_type) {
219		case KTYPE_KANIN:	/* Kanji Invoke sequence */
220			switch (c) {
221			case 'B':
222			case '@':
223				tcp->kanji_type = KTYPE_7JIS;
224				tcp->esc = 0;
225				tcp->kanji_1st_char = 0;
226				return;
227			default:
228				tcp->kanji_type = KTYPE_ASCII;
229				tcp->esc = 0;
230				break;
231			}
232			break;
233		case KTYPE_ASCIN:	/* Ascii Invoke sequence */
234			switch (c) {
235			case 'J':
236			case 'B':
237			case 'H':
238				tcp->kanji_type = KTYPE_ASCII;
239				tcp->esc = 0;
240				tcp->kanji_1st_char = 0;
241				return;
242			case 'I':
243				tcp->kanji_type = KTYPE_JKANA;
244				tcp->esc = 0;
245				tcp->kanji_1st_char = 0;
246				return;
247			default:
248				tcp->kanji_type = KTYPE_ASCII;
249				tcp->esc = 0;
250				break;
251			}
252			break;
253		default:
254			break;
255		}
256#endif
257		switch (c) {
258
259		case '7':	/* Save cursor position */
260			tcp->saved_xpos = scp->xpos;
261			tcp->saved_ypos = scp->ypos;
262			break;
263
264		case '8':	/* Restore saved cursor position */
265			if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
266				sc_move_cursor(scp, tcp->saved_xpos,
267					       tcp->saved_ypos);
268			break;
269
270		case '[':	/* Start ESC [ sequence */
271			tcp->esc = 2;
272			tcp->last_param = -1;
273			for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
274				tcp->param[i] = 1;
275			tcp->num_param = 0;
276			return;
277
278#ifdef KANJI
279		case '$':	/* Kanji Invoke sequence */
280			tcp->kanji_type = KTYPE_KANIN;
281			return;
282#endif
283
284		case 'M':	/* Move cursor up 1 line, scroll if at top */
285			sc_term_up_scroll(scp, 1, sc->scr_map[0x20],
286					  tcp->cur_attr, 0, 0);
287			break;
288#if notyet
289		case 'Q':
290			tcp->esc = 4;
291			return;
292#endif
293		case 'c':	/* Clear screen & home */
294			sc_clear_screen(scp);
295			break;
296
297		case '(':	/* iso-2022: designate 94 character set to G0 */
298#ifdef KANJI
299			tcp->kanji_type = KTYPE_ASCIN;
300#else
301			tcp->esc = 5;
302#endif
303			return;
304		}
305	} else if (tcp->esc == 2) {	/* seen ESC [ */
306		if (c >= '0' && c <= '9') {
307			if (tcp->num_param < MAX_ESC_PAR) {
308				if (tcp->last_param != tcp->num_param) {
309					tcp->last_param = tcp->num_param;
310					tcp->param[tcp->num_param] = 0;
311				} else {
312					tcp->param[tcp->num_param] *= 10;
313				}
314				tcp->param[tcp->num_param] += c - '0';
315				return;
316			}
317		}
318		tcp->num_param = tcp->last_param + 1;
319		switch (c) {
320
321		case ';':
322			if (tcp->num_param < MAX_ESC_PAR)
323				return;
324			break;
325
326		case '=':
327			tcp->esc = 3;
328			tcp->last_param = -1;
329			for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
330				tcp->param[i] = 1;
331			tcp->num_param = 0;
332			return;
333
334		case 'A':	/* up n rows */
335			sc_term_up(scp, tcp->param[0], 0);
336			break;
337
338		case 'B':	/* down n rows */
339			sc_term_down(scp, tcp->param[0], 0);
340			break;
341
342		case 'C':	/* right n columns */
343			sc_term_right(scp, tcp->param[0]);
344			break;
345
346		case 'D':	/* left n columns */
347			sc_term_left(scp, tcp->param[0]);
348			break;
349
350		case 'E':	/* cursor to start of line n lines down */
351			n = tcp->param[0];
352			if (n < 1)
353				n = 1;
354			sc_move_cursor(scp, 0, scp->ypos + n);
355			break;
356
357		case 'F':	/* cursor to start of line n lines up */
358			n = tcp->param[0];
359			if (n < 1)
360				n = 1;
361			sc_move_cursor(scp, 0, scp->ypos - n);
362			break;
363
364		case 'f':	/* Cursor move */
365		case 'H':
366			if (tcp->num_param == 0)
367				sc_move_cursor(scp, 0, 0);
368			else if (tcp->num_param == 2)
369				sc_move_cursor(scp, tcp->param[1] - 1,
370					       tcp->param[0] - 1);
371			break;
372
373		case 'J':	/* Clear all or part of display */
374			if (tcp->num_param == 0)
375				n = 0;
376			else
377				n = tcp->param[0];
378			sc_term_clr_eos(scp, n, sc->scr_map[0x20],
379					tcp->cur_attr);
380			break;
381
382		case 'K':	/* Clear all or part of line */
383			if (tcp->num_param == 0)
384				n = 0;
385			else
386				n = tcp->param[0];
387			sc_term_clr_eol(scp, n, sc->scr_map[0x20],
388					tcp->cur_attr);
389			break;
390
391		case 'L':	/* Insert n lines */
392			sc_term_ins_line(scp, scp->ypos, tcp->param[0],
393					 sc->scr_map[0x20], tcp->cur_attr, 0);
394			break;
395
396		case 'M':	/* Delete n lines */
397			sc_term_del_line(scp, scp->ypos, tcp->param[0],
398					 sc->scr_map[0x20], tcp->cur_attr, 0);
399			break;
400
401		case 'P':	/* Delete n chars */
402			sc_term_del_char(scp, tcp->param[0],
403					 sc->scr_map[0x20], tcp->cur_attr);
404			break;
405
406		case '@':	/* Insert n chars */
407			sc_term_ins_char(scp, tcp->param[0],
408					 sc->scr_map[0x20], tcp->cur_attr);
409			break;
410
411		case 'S':	/* scroll up n lines */
412			sc_term_del_line(scp, 0, tcp->param[0],
413					 sc->scr_map[0x20], tcp->cur_attr, 0);
414			break;
415
416		case 'T':	/* scroll down n lines */
417			sc_term_ins_line(scp, 0, tcp->param[0],
418					 sc->scr_map[0x20], tcp->cur_attr, 0);
419			break;
420
421		case 'X':	/* erase n characters in line */
422			n = tcp->param[0];
423			if (n < 1)
424				n = 1;
425			if (n > scp->xsize - scp->xpos)
426				n = scp->xsize - scp->xpos;
427			sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
428				     sc->scr_map[0x20], tcp->cur_attr);
429			mark_for_update(scp, scp->cursor_pos);
430			mark_for_update(scp, scp->cursor_pos + n - 1);
431			break;
432
433		case 'Z':	/* move n tabs backwards */
434			sc_term_backtab(scp, tcp->param[0]);
435			break;
436
437		case '`':	/* move cursor to column n */
438			sc_term_col(scp, tcp->param[0]);
439			break;
440
441		case 'a':	/* move cursor n columns to the right */
442			sc_term_right(scp, tcp->param[0]);
443			break;
444
445		case 'd':	/* move cursor to row n */
446			sc_term_row(scp, tcp->param[0]);
447			break;
448
449		case 'e':	/* move cursor n rows down */
450			sc_term_down(scp, tcp->param[0], 0);
451			break;
452
453		case 'm':	/* change attribute */
454			if (tcp->num_param == 0) {
455				tcp->attr_mask = NORMAL_ATTR;
456				tcp->cur_color = tcp->std_color;
457				tcp->cur_attr = mask2attr(tcp);
458				break;
459			}
460			for (i = 0; i < tcp->num_param; i++) {
461				switch (n = tcp->param[i]) {
462				case 0:	/* back to normal */
463					tcp->attr_mask = NORMAL_ATTR;
464					tcp->cur_color = tcp->std_color;
465					tcp->cur_attr = mask2attr(tcp);
466					break;
467				case 1:	/* bold */
468					tcp->attr_mask |= BOLD_ATTR;
469					tcp->cur_attr = mask2attr(tcp);
470					break;
471				case 4:	/* underline */
472					tcp->attr_mask |= UNDERLINE_ATTR;
473					tcp->cur_attr = mask2attr(tcp);
474					break;
475				case 5:	/* blink */
476					tcp->attr_mask |= BLINK_ATTR;
477					tcp->cur_attr = mask2attr(tcp);
478					break;
479				case 7:	/* reverse video */
480					tcp->attr_mask |= REVERSE_ATTR;
481					tcp->cur_attr = mask2attr(tcp);
482					break;
483				case 30: case 31: /* set fg color */
484				case 32: case 33: case 34:
485				case 35: case 36: case 37:
486					tcp->attr_mask |= FG_CHANGED;
487					tcp->cur_color.fg = ansi_col[n - 30];
488					tcp->cur_attr = mask2attr(tcp);
489					break;
490				case 39:
491					tcp->attr_mask &= ~FG_CHANGED;
492					tcp->cur_color.fg = tcp->std_color.fg;
493					tcp->cur_attr = mask2attr(tcp);
494					break;
495				case 40: case 41: /* set bg color */
496				case 42: case 43: case 44:
497				case 45: case 46: case 47:
498					tcp->attr_mask |= BG_CHANGED;
499					tcp->cur_color.bg = ansi_col[n - 40];
500					tcp->cur_attr = mask2attr(tcp);
501					break;
502				case 49:
503					tcp->attr_mask &= ~BG_CHANGED;
504					tcp->cur_color.bg = tcp->std_color.bg;
505					tcp->cur_attr = mask2attr(tcp);
506					break;
507				}
508			}
509			break;
510
511		case 's':	/* Save cursor position */
512			tcp->saved_xpos = scp->xpos;
513			tcp->saved_ypos = scp->ypos;
514			break;
515
516		case 'u':	/* Restore saved cursor position */
517			if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
518				sc_move_cursor(scp, tcp->saved_xpos,
519					       tcp->saved_ypos);
520			break;
521
522		case 'x':
523			if (tcp->num_param == 0)
524				n = 0;
525			else
526				n = tcp->param[0];
527			switch (n) {
528			case 0: /* reset colors and attributes */
529				tcp->attr_mask = NORMAL_ATTR;
530				tcp->cur_color = tcp->std_color =
531				    tcp->dflt_std_color;
532				tcp->rev_color = tcp->dflt_rev_color;
533				tcp->cur_attr = mask2attr(tcp);
534				break;
535			case 1:	/* set ansi background */
536				tcp->attr_mask &= ~BG_CHANGED;
537				tcp->cur_color.bg = tcp->std_color.bg =
538				    ansi_col[tcp->param[1] & 0x0f];
539				tcp->cur_attr = mask2attr(tcp);
540				break;
541			case 2:	/* set ansi foreground */
542				tcp->attr_mask &= ~FG_CHANGED;
543				tcp->cur_color.fg = tcp->std_color.fg =
544				    ansi_col[tcp->param[1] & 0x0f];
545				tcp->cur_attr = mask2attr(tcp);
546				break;
547			case 3: /* set video attribute directly */
548				tcp->attr_mask &= ~(FG_CHANGED | BG_CHANGED);
549				tcp->cur_color.fg = tcp->std_color.fg =
550				    tcp->param[1] & 0x0f;
551				tcp->cur_color.bg = tcp->std_color.bg =
552				    (tcp->param[1] >> 4) & 0x0f;
553				tcp->cur_attr = mask2attr(tcp);
554				break;
555			case 5:	/* set ansi reverse video background */
556				tcp->rev_color.bg =
557				    ansi_col[tcp->param[1] & 0x0f];
558				tcp->cur_attr = mask2attr(tcp);
559				break;
560			case 6:	/* set ansi reverse video foreground */
561				tcp->rev_color.fg =
562				    ansi_col[tcp->param[1] & 0x0f];
563				tcp->cur_attr = mask2attr(tcp);
564				break;
565			case 7: /* set reverse video attribute directly */
566				tcp->rev_color.fg = tcp->param[1] & 0x0f;
567				tcp->rev_color.bg = (tcp->param[1] >> 4) & 0x0f;
568				tcp->cur_attr = mask2attr(tcp);
569				break;
570			}
571			break;
572
573		case 'z':	/* switch to (virtual) console n */
574			if (tcp->num_param == 1)
575				sc_switch_scr(sc, tcp->param[0]);
576			break;
577		}
578	} else if (tcp->esc == 3) {	/* seen ESC [0-9]+ = */
579		if (c >= '0' && c <= '9') {
580			if (tcp->num_param < MAX_ESC_PAR) {
581				if (tcp->last_param != tcp->num_param) {
582					tcp->last_param = tcp->num_param;
583					tcp->param[tcp->num_param] = 0;
584				} else {
585					tcp->param[tcp->num_param] *= 10;
586				}
587				tcp->param[tcp->num_param] += c - '0';
588				return;
589			}
590		}
591		tcp->num_param = tcp->last_param + 1;
592		switch (c) {
593
594		case ';':
595			if (tcp->num_param < MAX_ESC_PAR)
596				return;
597			break;
598
599		case 'A':   /* set display border color */
600			if (tcp->num_param == 1) {
601				scp->border=tcp->param[0] & 0xff;
602				if (scp == sc->cur_scp)
603					sc_set_border(scp, scp->border);
604			}
605			break;
606
607		case 'B':   /* set bell pitch and duration */
608			if (tcp->num_param == 2) {
609				scp->bell_pitch = tcp->param[0];
610				scp->bell_duration = tcp->param[1];
611			}
612			break;
613
614		case 'C':   /* set cursor type & shape */
615			i = spltty();
616			if (!ISGRAPHSC(sc->cur_scp))
617				sc_remove_cursor_image(sc->cur_scp);
618			if (tcp->num_param == 1) {
619				if (tcp->param[0] & 0x01)
620					sc->flags |= SC_BLINK_CURSOR;
621				else
622					sc->flags &= ~SC_BLINK_CURSOR;
623				if (tcp->param[0] & 0x02)
624					sc->flags |= SC_CHAR_CURSOR;
625				else
626					sc->flags &= ~SC_CHAR_CURSOR;
627			} else if (tcp->num_param == 2) {
628				sc->cursor_base = scp->font_size
629						- (tcp->param[1] & 0x1F) - 1;
630				sc->cursor_height = (tcp->param[1] & 0x1F)
631						- (tcp->param[0] & 0x1F) + 1;
632			}
633			/*
634			 * The cursor shape is global property;
635			 * all virtual consoles are affected.
636			 * Update the cursor in the current console...
637			 */
638			if (!ISGRAPHSC(sc->cur_scp)) {
639				sc_set_cursor_image(sc->cur_scp);
640				sc_draw_cursor_image(sc->cur_scp);
641			}
642			splx(i);
643			break;
644
645		case 'F':   /* set foreground */
646			if (tcp->num_param == 1) {
647				tcp->attr_mask &= ~FG_CHANGED;
648				tcp->cur_color.fg = tcp->std_color.fg =
649				    tcp->param[0] & 0x0f;
650				tcp->cur_attr = mask2attr(tcp);
651			}
652			break;
653
654		case 'G':   /* set background */
655			if (tcp->num_param == 1) {
656				tcp->attr_mask &= ~BG_CHANGED;
657				tcp->cur_color.bg = tcp->std_color.bg =
658				    tcp->param[0] & 0x0f;
659				tcp->cur_attr = mask2attr(tcp);
660			}
661			break;
662
663		case 'H':   /* set reverse video foreground */
664			if (tcp->num_param == 1) {
665				tcp->rev_color.fg = tcp->param[0] & 0x0f;
666				tcp->cur_attr = mask2attr(tcp);
667			}
668			break;
669
670		case 'I':   /* set reverse video background */
671			if (tcp->num_param == 1) {
672				tcp->rev_color.bg = tcp->param[0] & 0x0f;
673				tcp->cur_attr = mask2attr(tcp);
674			}
675			break;
676		}
677#if notyet
678	} else if (tcp->esc == 4) {	/* seen ESC Q */
679		/* to be filled */
680#endif
681	} else if (tcp->esc == 5) {	/* seen ESC ( */
682		switch (c) {
683		case 'B':   /* iso-2022: desginate ASCII into G0 */
684			break;
685		/* other items to be filled */
686		default:
687			break;
688		}
689	}
690	tcp->esc = 0;
691}
692
693static void
694scterm_puts(scr_stat *scp, u_char *buf, int len)
695{
696	term_stat *tcp = scp->ts;
697	u_char *ptr = buf;
698#ifdef KANJI
699	u_short kanji_code;
700#endif
701
702outloop:
703	scp->sc->write_in_progress++;
704
705	if (tcp->esc) {
706		scterm_scan_esc(scp, tcp, *ptr++);
707		len--;
708	} else if (PRINTABLE(*ptr)) {     /* Print only printables */
709		vm_offset_t p;
710		u_char *map;
711		int attr;
712		int i;
713#ifdef KANJI
714		u_char c;
715#else
716		int cnt;
717#endif
718
719		p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
720		map = scp->sc->scr_map;
721		attr = tcp->cur_attr;
722
723#ifdef KANJI
724		c = *ptr;
725		if (tcp->kanji_1st_char == 0) {
726		    tcp->kanji_type = iskanji1(tcp->kanji_type, c);
727		    if (!IS_KTYPE_ASCII_or_HANKAKU(tcp->kanji_type)) {
728			/* not Ascii & not HANKAKU */
729			tcp->kanji_1st_char = c;
730			goto kanji_end;
731		    } else {
732			tcp->kanji_1st_char = 0;
733		    }
734		} else {
735		    if ((tcp->kanji_type =
736			 iskanji2(tcp->kanji_type, c)) & 0xee) {
737			/* print kanji on TEXT VRAM */
738			kanji_code = kanji_convert(tcp->kanji_type, c,
739						   tcp->kanji_1st_char);
740			mark_for_update(scp, scp->cursor_pos);
741			for (i = 0; i < 2; i++) {
742			    /* *cursor_pos = (kanji_code | (i*0x80)); */
743			    p = sc_vtb_putchar(&scp->vtb, p,
744			       kanji_code | ((i == 0) ? 0x00 : 0x80), attr);
745			    ++scp->cursor_pos;
746			    if (++scp->xpos >= scp->xsize) {
747				scp->xpos = 0;
748				scp->ypos++;
749			    }
750			}
751			mark_for_update(scp, scp->cursor_pos - 1);
752			KTYPE_MASK_CTRL(tcp->kanji_type);
753			tcp->kanji_1st_char = 0;
754			goto kanji_end;
755		    } else {
756			tcp->kanji_1st_char = 0;
757		    }
758		}
759		if (IS_KTYPE_KANA(tcp->kanji_type))
760		    c |= 0x80;
761		KTYPE_MASK_CTRL(tcp->kanji_type);
762		sc_vtb_putchar(&scp->vtb, p, map[c], attr);
763		mark_for_update(scp, scp->cursor_pos);
764		mark_for_update(scp, scp->cursor_pos);
765		++scp->cursor_pos;
766		++scp->xpos;
767kanji_end:
768		++ptr;
769		--len;
770#else /* !KANJI */
771		cnt = imin(len, scp->xsize - scp->xpos);
772		i = cnt;
773		do {
774		    /*
775		     * gcc-2.6.3 generates poor (un)sign extension code.
776		     * Casting the pointers in the following to volatile should
777		     * have no effect, but in fact speeds up this inner loop
778		     * from 26 to 18 cycles (+ cache misses) on i486's.
779		     */
780#define	UCVP(ucp)	((u_char volatile *)(ucp))
781		    p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)],
782				       attr);
783		    ++ptr;
784		    --i;
785		} while (i > 0 && PRINTABLE(*ptr));
786
787		len -= cnt - i;
788		mark_for_update(scp, scp->cursor_pos);
789		scp->cursor_pos += cnt - i;
790		mark_for_update(scp, scp->cursor_pos - 1);
791		scp->xpos += cnt - i;
792#endif /* !KANJI */
793
794		if (scp->xpos >= scp->xsize) {
795			scp->xpos = 0;
796			scp->ypos++;
797		}
798	} else {
799		switch (*ptr) {
800		case 0x07:
801			sc_bell(scp, scp->bell_pitch, scp->bell_duration);
802			break;
803
804		case 0x08:	/* non-destructive backspace */
805			if (scp->cursor_pos > 0) {
806				mark_for_update(scp, scp->cursor_pos);
807				scp->cursor_pos--;
808				mark_for_update(scp, scp->cursor_pos);
809				if (scp->xpos > 0)
810					scp->xpos--;
811				else {
812					scp->xpos += scp->xsize - 1;
813					scp->ypos--;
814				}
815			}
816			break;
817
818		case 0x09:	/* non-destructive tab */
819			mark_for_update(scp, scp->cursor_pos);
820			scp->cursor_pos += (8 - scp->xpos % 8u);
821			scp->xpos += (8 - scp->xpos % 8u);
822			if (scp->xpos >= scp->xsize) {
823				scp->xpos = 0;
824				scp->ypos++;
825				scp->cursor_pos = scp->xsize * scp->ypos;
826			}
827			mark_for_update(scp, scp->cursor_pos);
828			break;
829
830		case 0x0a:	/* newline, same pos */
831			mark_for_update(scp, scp->cursor_pos);
832			scp->cursor_pos += scp->xsize;
833			mark_for_update(scp, scp->cursor_pos);
834			scp->ypos++;
835			break;
836
837		case 0x0c:	/* form feed, clears screen */
838			sc_clear_screen(scp);
839			break;
840
841		case 0x0d:	/* return, return to pos 0 */
842			mark_for_update(scp, scp->cursor_pos);
843			scp->cursor_pos -= scp->xpos;
844			mark_for_update(scp, scp->cursor_pos);
845			scp->xpos = 0;
846			break;
847
848#ifdef PC98
849		case 0x0e:	/* ^N */
850		tcp->kanji_type = KTYPE_JKANA;
851		tcp->esc = 0;
852		tcp->kanji_1st_char = 0;
853		break;
854
855		case 0x0f:	/* ^O */
856			tcp->kanji_type = KTYPE_ASCII;
857			tcp->esc = 0;
858			tcp->kanji_1st_char = 0;
859			break;
860#endif /* PC98 */
861
862		case 0x1b:	/* start escape sequence */
863			tcp->esc = 1;
864			tcp->num_param = 0;
865			break;
866		}
867		ptr++;
868		len--;
869	}
870
871	sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
872
873	scp->sc->write_in_progress--;
874	if (len)
875		goto outloop;
876}
877
878static int
879scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
880	     int flag, struct proc *p)
881{
882	term_stat *tcp = scp->ts;
883	vid_info_t *vi;
884
885	switch (cmd) {
886	case GIO_ATTR:      	/* get current attributes */
887		/* FIXME: */
888		*(int*)data = (tcp->cur_attr >> 8) & 0xff;
889		return 0;
890	case CONS_GETINFO:  	/* get current (virtual) console info */
891		vi = (vid_info_t *)data;
892		if (vi->size != sizeof(struct vid_info))
893			return EINVAL;
894		vi->mv_norm.fore = tcp->std_color.fg;
895		vi->mv_norm.back = tcp->std_color.bg;
896		vi->mv_rev.fore = tcp->rev_color.fg;
897		vi->mv_rev.back = tcp->rev_color.bg;
898		/*
899		 * The other fields are filled by the upper routine. XXX
900		 */
901		return ENOIOCTL;
902	}
903	return ENOIOCTL;
904}
905
906static int
907scterm_reset(scr_stat *scp, int code)
908{
909	/* FIXME */
910	return 0;
911}
912
913static void
914scterm_default_attr(scr_stat *scp, int color, int rev_color)
915{
916	term_stat *tcp = scp->ts;
917
918	tcp->dflt_std_color.fg = color & 0x0f;
919	tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
920	tcp->dflt_rev_color.fg = rev_color & 0x0f;
921	tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
922	tcp->std_color = tcp->dflt_std_color;
923	tcp->rev_color = tcp->dflt_rev_color;
924	tcp->cur_color = tcp->std_color;
925	tcp->cur_attr = mask2attr(tcp);
926}
927
928static void
929scterm_clear(scr_stat *scp)
930{
931	term_stat *tcp = scp->ts;
932
933	sc_move_cursor(scp, 0, 0);
934	sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
935	mark_all(scp);
936}
937
938static void
939scterm_notify(scr_stat *scp, int event)
940{
941	switch (event) {
942	case SC_TE_NOTIFY_VTSWITCH_IN:
943		break;
944	case SC_TE_NOTIFY_VTSWITCH_OUT:
945		break;
946	}
947}
948
949static int
950scterm_input(scr_stat *scp, int c, struct tty *tp)
951{
952	return FALSE;
953}
954
955/*
956 * Calculate hardware attributes word using logical attributes mask and
957 * hardware colors
958 */
959
960/* FIXME */
961static int
962mask2attr(term_stat *tcp)
963{
964	int attr, mask = tcp->attr_mask;
965
966	if (mask & REVERSE_ATTR) {
967		attr = ((mask & FG_CHANGED) ?
968			tcp->cur_color.bg : tcp->rev_color.fg) |
969			(((mask & BG_CHANGED) ?
970			tcp->cur_color.fg : tcp->rev_color.bg) << 4);
971	} else
972		attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
973
974	/* XXX: underline mapping for Hercules adapter can be better */
975	if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
976		attr ^= 0x08;
977	if (mask & BLINK_ATTR)
978		attr ^= 0x80;
979
980	return (attr << 8);
981}
982
983#ifdef KANJI
984static u_char
985iskanji1(u_char mode, u_char c)
986{
987    if ((mode == KTYPE_7JIS) && (c >= 0x21) && (c <= 0x7e)) {
988	/* JIS */
989	default_kanji = UJIS;
990	return KTYPE_7JIS;
991    }
992
993    if ((mode == KTYPE_JKANA) && (c >= 0x21) && (c <= 0x5f)) {
994	/* JIS HANKAKU */
995	default_kanji = UJIS;
996	return KTYPE_JKANA;
997    }
998
999#if 1
1000    if ((c >= 0xa1) && (c <= 0xdf) && (default_kanji == UJIS)) {
1001	/* UJIS */
1002	return KTYPE_UJIS;
1003    }
1004#endif
1005
1006    if ((c >= 0x81) && (c <= 0x9f) && (c != 0x8e)) {
1007	/* SJIS */
1008	default_kanji = SJIS;
1009	return KTYPE_SJIS;
1010    }
1011
1012    if ((c >= 0xa1) && (c <= 0xdf) && (default_kanji == SJIS)) {
1013	/* SJIS HANKAKU */
1014	return KTYPE_KANA;
1015    }
1016
1017#if 0
1018    if ((c >= 0xa1) && (c <= 0xdf) && (default_kanji == UJIS)) {
1019	/* UJIS */
1020	return KTYPE_UJIS;
1021    }
1022#endif
1023
1024    if ((c >= 0xf0) && (c <= 0xfe)) {
1025	/* UJIS */
1026	default_kanji = UJIS;
1027	return KTYPE_UJIS;
1028    }
1029
1030    if ((c >= 0xe0) && (c <= 0xef)) {
1031	/* SJIS or UJIS */
1032	return KTYPE_SUJIS;
1033    }
1034
1035    if (c == 0x8e) {
1036	/* SJIS or UJIS HANKAKU */
1037	return KTYPE_SUKANA;
1038    }
1039
1040    return KTYPE_ASCII;
1041}
1042
1043static u_char
1044iskanji2(u_char mode, u_char c)
1045{
1046    switch (mode) {
1047    case KTYPE_7JIS:
1048	if ((c >= 0x21) && (c <= 0x7e)) {
1049	    /* JIS */
1050	    return KTYPE_7JIS;
1051	}
1052	break;
1053    case KTYPE_SJIS:
1054	if ((c >= 0x40) && (c <= 0xfc) && (c != 0x7f)) {
1055	    /* SJIS */
1056	    return KTYPE_SJIS;
1057	}
1058	break;
1059    case KTYPE_UJIS:
1060	if ((c >= 0xa1) && (c <= 0xfe)) {
1061	    /* UJIS */
1062	    return KTYPE_UJIS;
1063	}
1064	break;
1065    case KTYPE_SUKANA:
1066	if ((c >= 0xa1) && (c <= 0xdf) && (default_kanji == UJIS)) {
1067	    /* UJIS HANKAKU */
1068	    return KTYPE_KANA;
1069	}
1070	if ((c >= 0x40) && (c <= 0xfc) && (c != 0x7f)) {
1071	    /* SJIS */
1072	    default_kanji = SJIS;
1073	    return KTYPE_SJIS;
1074	}
1075	break;
1076    case KTYPE_SUJIS:
1077	if ((c >= 0x40) && (c <= 0xa0) && (c != 0x7f)) {
1078	    /* SJIS */
1079	    default_kanji = SJIS;
1080	    return KTYPE_SJIS;
1081	}
1082	if ((c == 0xfd) || (c == 0xfe)) {
1083	    /* UJIS */
1084	    default_kanji = UJIS;
1085	    return KTYPE_UJIS;
1086	}
1087	if ((c >= 0xa1) && (c <= 0xfc)) {
1088	    if (default_kanji == SJIS)
1089		return KTYPE_SJIS;
1090	    if (default_kanji == UJIS)
1091		return KTYPE_UJIS;
1092	}
1093	break;
1094    }
1095    return KTYPE_ASCII;
1096}
1097
1098/*
1099 * JIS X0208-83 keisen conversion table
1100 */
1101static u_short keiConv[32] = {
1102	0x240c, 0x260c, 0x300c, 0x340c, 0x3c0c, 0x380c, 0x400c, 0x500c,
1103	0x480c, 0x580c, 0x600c, 0x250c, 0x270c, 0x330c, 0x370c, 0x3f0c,
1104	0x3b0c, 0x470c, 0x570c, 0x4f0c, 0x5f0c, 0x6f0c, 0x440c, 0x530c,
1105	0x4c0c, 0x5b0c, 0x630c, 0x410c, 0x540c, 0x490c, 0x5c0c, 0x660c
1106};
1107
1108static u_short
1109kanji_convert(u_char mode, u_char h, u_char l)
1110{
1111    u_short tmp, high, low, c;
1112    high = (u_short) h;
1113    low  = (u_short) l;
1114
1115    switch (mode) {
1116    case KTYPE_SJIS: /* SHIFT JIS */
1117	if (low >= 0xe0) {
1118	    low -= 0x40;
1119	}
1120	low = (low - 0x81) * 2 + 0x21;
1121	if (high > 0x7f) {
1122	    high--;
1123	}
1124	if (high > 0x9d) {
1125	    low++;
1126	    high -= 0x9e - 0x21;
1127	} else {
1128	    high -= 0x40 - 0x21;
1129	}
1130	high &= 0x7F;
1131	low  &= 0x7F;
1132	tmp = ((high << 8) | low) - 0x20;
1133	break;
1134    case KTYPE_7JIS: /* JIS */
1135    case KTYPE_UJIS: /* UJIS */
1136	high &= 0x7F;
1137	low &= 0x7F;
1138	tmp = ((high << 8) | low) - 0x20;
1139	break;
1140    default:
1141	tmp = 0;
1142	break;
1143    }
1144
1145    /* keisen */
1146    c = ((tmp & 0xff) << 8) | (tmp >> 8);
1147    /* 0x2821 .. 0x2840 */
1148    if (0x0821 <= c && c <= 0x0840)
1149    tmp = keiConv[c - 0x0821];
1150
1151    return (tmp);
1152}
1153#endif /* KANJI */
1154
1155#endif /* SC_DUMB_TERMINAL */
1156