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