xref: /dragonfly/sys/dev/misc/syscons/scterm-sc.c (revision f746689a)
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * Copyright (c) 1992-1998 S�ren Schmidt
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer as
11  *    the first lines of this file unmodified.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/dev/syscons/scterm-sc.c,v 1.4.2.10 2001/06/11 09:05:39 phk Exp $
28  * $DragonFly: src/sys/dev/misc/syscons/scterm-sc.c,v 1.8 2008/08/10 19:47:31 swildner Exp $
29  */
30 
31 #include "opt_syscons.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/consio.h>
37 #include <sys/thread2.h>
38 
39 #include <machine/pc/display.h>
40 
41 #include "syscons.h"
42 #include "sctermvar.h"
43 
44 #ifndef SC_DUMB_TERMINAL
45 
46 #define MAX_ESC_PAR	5
47 
48 /* attribute flags */
49 typedef struct {
50 	u_short		fg;			/* foreground color */
51 	u_short		bg;			/* background color */
52 } color_t;
53 
54 typedef struct {
55 	int		flags;
56 #define SCTERM_BUSY	(1 << 0)
57 	int		esc;
58 	int		num_param;
59 	int		last_param;
60 	int		param[MAX_ESC_PAR];
61 	int		saved_xpos;
62 	int		saved_ypos;
63 	int		attr_mask;		/* current logical attr mask */
64 #define NORMAL_ATTR	0x00
65 #define BLINK_ATTR	0x01
66 #define BOLD_ATTR	0x02
67 #define UNDERLINE_ATTR	0x04
68 #define REVERSE_ATTR	0x08
69 #define FG_CHANGED	0x10
70 #define BG_CHANGED	0x20
71 	int		cur_attr;		/* current hardware attr word */
72 	color_t		cur_color;		/* current hardware color */
73 	color_t		std_color;		/* normal hardware color */
74 	color_t		rev_color;		/* reverse hardware color */
75 	color_t		dflt_std_color;		/* default normal color */
76 	color_t		dflt_rev_color;		/* default reverse color */
77 } term_stat;
78 
79 static sc_term_init_t	scterm_init;
80 static sc_term_term_t	scterm_term;
81 static sc_term_puts_t	scterm_puts;
82 static sc_term_ioctl_t	scterm_ioctl;
83 static sc_term_reset_t	scterm_reset;
84 static sc_term_default_attr_t	scterm_default_attr;
85 static sc_term_clear_t	scterm_clear;
86 static sc_term_notify_t	scterm_notify;
87 static sc_term_input_t	scterm_input;
88 
89 static sc_term_sw_t sc_term_sc = {
90 	{ NULL, NULL },
91 	"sc",					/* emulator name */
92 	"syscons terminal",			/* description */
93 	"*",					/* matching renderer, any :-) */
94 	sizeof(term_stat),			/* softc size */
95 	0,
96 	scterm_init,
97 	scterm_term,
98 	scterm_puts,
99 	scterm_ioctl,
100 	scterm_reset,
101 	scterm_default_attr,
102 	scterm_clear,
103 	scterm_notify,
104 	scterm_input,
105 };
106 
107 SCTERM_MODULE(sc, sc_term_sc);
108 
109 static term_stat	reserved_term_stat;
110 static void		scterm_scan_esc(scr_stat *scp, term_stat *tcp,
111 					u_char c);
112 static int		mask2attr(term_stat *tcp);
113 
114 static int
115 scterm_init(scr_stat *scp, void **softc, int code)
116 {
117 	term_stat *tcp;
118 
119 	if (*softc == NULL) {
120 		if (reserved_term_stat.flags & SCTERM_BUSY)
121 			return EINVAL;
122 		*softc = &reserved_term_stat;
123 	}
124 	tcp = *softc;
125 
126 	switch (code) {
127 	case SC_TE_COLD_INIT:
128 		bzero(tcp, sizeof(*tcp));
129 		tcp->flags = SCTERM_BUSY;
130 		tcp->esc = 0;
131 		tcp->saved_xpos = -1;
132 		tcp->saved_ypos = -1;
133 		tcp->attr_mask = NORMAL_ATTR;
134 		/* XXX */
135 		tcp->dflt_std_color.fg = SC_NORM_ATTR & 0x0f;
136 		tcp->dflt_std_color.bg = (SC_NORM_ATTR >> 4) & 0x0f;
137 		tcp->dflt_rev_color.fg = SC_NORM_REV_ATTR & 0x0f;
138 		tcp->dflt_rev_color.bg = (SC_NORM_REV_ATTR >> 4) & 0x0f;
139 		tcp->std_color = tcp->dflt_std_color;
140 		tcp->rev_color = tcp->dflt_rev_color;
141 		tcp->cur_color = tcp->std_color;
142 		tcp->cur_attr = mask2attr(tcp);
143 		++sc_term_sc.te_refcount;
144 		break;
145 
146 	case SC_TE_WARM_INIT:
147 		tcp->esc = 0;
148 		tcp->saved_xpos = -1;
149 		tcp->saved_ypos = -1;
150 #if 0
151 		tcp->std_color = tcp->dflt_std_color;
152 		tcp->rev_color = tcp->dflt_rev_color;
153 #endif
154 		tcp->cur_color = tcp->std_color;
155 		tcp->cur_attr = mask2attr(tcp);
156 		break;
157 	}
158 
159 	return 0;
160 }
161 
162 static int
163 scterm_term(scr_stat *scp, void **softc)
164 {
165 	if (*softc == &reserved_term_stat) {
166 		*softc = NULL;
167 		bzero(&reserved_term_stat, sizeof(reserved_term_stat));
168 	}
169 	--sc_term_sc.te_refcount;
170 	return 0;
171 }
172 
173 static void
174 scterm_scan_esc(scr_stat *scp, term_stat *tcp, u_char c)
175 {
176 	static u_char ansi_col[16] = {
177 		FG_BLACK,     FG_RED,          FG_GREEN,      FG_BROWN,
178 		FG_BLUE,      FG_MAGENTA,      FG_CYAN,       FG_LIGHTGREY,
179 		FG_DARKGREY,  FG_LIGHTRED,     FG_LIGHTGREEN, FG_YELLOW,
180 		FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN,  FG_WHITE
181 	};
182 	sc_softc_t *sc;
183 	int i, n;
184 
185 	sc = scp->sc;
186 	if (tcp->esc == 1) {	/* seen ESC */
187 		switch (c) {
188 
189 		case '7':	/* Save cursor position */
190 			tcp->saved_xpos = scp->xpos;
191 			tcp->saved_ypos = scp->ypos;
192 			break;
193 
194 		case '8':	/* Restore saved cursor position */
195 			if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
196 				sc_move_cursor(scp, tcp->saved_xpos,
197 					       tcp->saved_ypos);
198 			break;
199 
200 		case '[':	/* Start ESC [ sequence */
201 			tcp->esc = 2;
202 			tcp->last_param = -1;
203 			for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
204 				tcp->param[i] = 1;
205 			tcp->num_param = 0;
206 			return;
207 
208 		case 'M':	/* Move cursor up 1 line, scroll if at top */
209 			sc_term_up_scroll(scp, 1, sc->scr_map[0x20],
210 					  tcp->cur_attr, 0, 0);
211 			break;
212 #if notyet
213 		case 'Q':
214 			tcp->esc = 4;
215 			return;
216 #endif
217 		case 'c':       /* reset */
218 			tcp->attr_mask = NORMAL_ATTR;
219 			tcp->cur_color = tcp->std_color
220 				       = tcp->dflt_std_color;
221 			tcp->rev_color = tcp->dflt_rev_color;
222 			tcp->cur_attr = mask2attr(tcp);
223 			sc_clear_screen(scp);
224 			break;
225 
226 		case '(':	/* iso-2022: designate 94 character set to G0 */
227 			tcp->esc = 5;
228 			return;
229 		}
230 	} else if (tcp->esc == 2) {	/* seen ESC [ */
231 		if (c >= '0' && c <= '9') {
232 			if (tcp->num_param < MAX_ESC_PAR) {
233 				if (tcp->last_param != tcp->num_param) {
234 					tcp->last_param = tcp->num_param;
235 					tcp->param[tcp->num_param] = 0;
236 				} else {
237 					tcp->param[tcp->num_param] *= 10;
238 				}
239 				tcp->param[tcp->num_param] += c - '0';
240 				return;
241 			}
242 		}
243 		tcp->num_param = tcp->last_param + 1;
244 		switch (c) {
245 
246 		case ';':
247 			if (tcp->num_param < MAX_ESC_PAR)
248 				return;
249 			break;
250 
251 		case '=':
252 			tcp->esc = 3;
253 			tcp->last_param = -1;
254 			for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
255 				tcp->param[i] = 1;
256 			tcp->num_param = 0;
257 			return;
258 
259 		case 'A':	/* up n rows */
260 			sc_term_up(scp, tcp->param[0], 0);
261 			break;
262 
263 		case 'B':	/* down n rows */
264 			sc_term_down(scp, tcp->param[0], 0);
265 			break;
266 
267 		case 'C':	/* right n columns */
268 			sc_term_right(scp, tcp->param[0]);
269 			break;
270 
271 		case 'D':	/* left n columns */
272 			sc_term_left(scp, tcp->param[0]);
273 			break;
274 
275 		case 'E':	/* cursor to start of line n lines down */
276 			n = tcp->param[0];
277 			if (n < 1)
278 				n = 1;
279 			sc_move_cursor(scp, 0, scp->ypos + n);
280 			break;
281 
282 		case 'F':	/* cursor to start of line n lines up */
283 			n = tcp->param[0];
284 			if (n < 1)
285 				n = 1;
286 			sc_move_cursor(scp, 0, scp->ypos - n);
287 			break;
288 
289 		case 'f':	/* Cursor move */
290 		case 'H':
291 			if (tcp->num_param == 0)
292 				sc_move_cursor(scp, 0, 0);
293 			else if (tcp->num_param == 2)
294 				sc_move_cursor(scp, tcp->param[1] - 1,
295 					       tcp->param[0] - 1);
296 			break;
297 
298 		case 'J':	/* Clear all or part of display */
299 			if (tcp->num_param == 0)
300 				n = 0;
301 			else
302 				n = tcp->param[0];
303 			sc_term_clr_eos(scp, n, sc->scr_map[0x20],
304 					tcp->cur_attr);
305 			break;
306 
307 		case 'K':	/* Clear all or part of line */
308 			if (tcp->num_param == 0)
309 				n = 0;
310 			else
311 				n = tcp->param[0];
312 			sc_term_clr_eol(scp, n, sc->scr_map[0x20],
313 					tcp->cur_attr);
314 			break;
315 
316 		case 'L':	/* Insert n lines */
317 			sc_term_ins_line(scp, scp->ypos, tcp->param[0],
318 					 sc->scr_map[0x20], tcp->cur_attr, 0);
319 			break;
320 
321 		case 'M':	/* Delete n lines */
322 			sc_term_del_line(scp, scp->ypos, tcp->param[0],
323 					 sc->scr_map[0x20], tcp->cur_attr, 0);
324 			break;
325 
326 		case 'P':	/* Delete n chars */
327 			sc_term_del_char(scp, tcp->param[0],
328 					 sc->scr_map[0x20], tcp->cur_attr);
329 			break;
330 
331 		case '@':	/* Insert n chars */
332 			sc_term_ins_char(scp, tcp->param[0],
333 					 sc->scr_map[0x20], tcp->cur_attr);
334 			break;
335 
336 		case 'S':	/* scroll up n lines */
337 			sc_term_del_line(scp, 0, tcp->param[0],
338 					 sc->scr_map[0x20], tcp->cur_attr, 0);
339 			break;
340 
341 		case 'T':	/* scroll down n lines */
342 			sc_term_ins_line(scp, 0, tcp->param[0],
343 					 sc->scr_map[0x20], tcp->cur_attr, 0);
344 			break;
345 
346 		case 'X':	/* erase n characters in line */
347 			n = tcp->param[0];
348 			if (n < 1)
349 				n = 1;
350 			if (n > scp->xsize - scp->xpos)
351 				n = scp->xsize - scp->xpos;
352 			sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
353 				     sc->scr_map[0x20], tcp->cur_attr);
354 			mark_for_update(scp, scp->cursor_pos);
355 			mark_for_update(scp, scp->cursor_pos + n - 1);
356 			break;
357 
358 		case 'Z':	/* move n tabs backwards */
359 			sc_term_backtab(scp, tcp->param[0]);
360 			break;
361 
362 		case '`':	/* move cursor to column n */
363 			sc_term_col(scp, tcp->param[0]);
364 			break;
365 
366 		case 'a':	/* move cursor n columns to the right */
367 			sc_term_right(scp, tcp->param[0]);
368 			break;
369 
370 		case 'd':	/* move cursor to row n */
371 			sc_term_row(scp, tcp->param[0]);
372 			break;
373 
374 		case 'e':	/* move cursor n rows down */
375 			sc_term_down(scp, tcp->param[0], 0);
376 			break;
377 
378 		case 'm':	/* change attribute */
379 			if (tcp->num_param == 0) {
380 				tcp->attr_mask = NORMAL_ATTR;
381 				tcp->cur_color = tcp->std_color;
382 				tcp->cur_attr = mask2attr(tcp);
383 				break;
384 			}
385 			for (i = 0; i < tcp->num_param; i++) {
386 				switch (n = tcp->param[i]) {
387 				case 0:	/* back to normal */
388 					tcp->attr_mask = NORMAL_ATTR;
389 					tcp->cur_color = tcp->std_color;
390 					tcp->cur_attr = mask2attr(tcp);
391 					break;
392 				case 1:	/* bold */
393 					tcp->attr_mask |= BOLD_ATTR;
394 					tcp->cur_attr = mask2attr(tcp);
395 					break;
396 				case 4:	/* underline */
397 					tcp->attr_mask |= UNDERLINE_ATTR;
398 					tcp->cur_attr = mask2attr(tcp);
399 					break;
400 				case 5:	/* blink */
401 					tcp->attr_mask |= BLINK_ATTR;
402 					tcp->cur_attr = mask2attr(tcp);
403 					break;
404 				case 7: /* reverse */
405 					tcp->attr_mask |= REVERSE_ATTR;
406 					tcp->cur_attr = mask2attr(tcp);
407 					break;
408 				case 22: /* remove bold (or dim) */
409 					tcp->attr_mask &= ~BOLD_ATTR;
410 					tcp->cur_attr = mask2attr(tcp);
411 					break;
412 				case 24: /* remove underline */
413 					tcp->attr_mask &= ~UNDERLINE_ATTR;
414 					tcp->cur_attr = mask2attr(tcp);
415 					break;
416 				case 25: /* remove blink */
417 					tcp->attr_mask &= ~BLINK_ATTR;
418 					tcp->cur_attr = mask2attr(tcp);
419 					break;
420 				case 27: /* remove reverse */
421 					tcp->attr_mask &= ~REVERSE_ATTR;
422 					tcp->cur_attr = mask2attr(tcp);
423 					break;
424 				case 30: case 31: /* set ansi fg color */
425 				case 32: case 33: case 34:
426 				case 35: case 36: case 37:
427 					tcp->attr_mask |= FG_CHANGED;
428 					tcp->cur_color.fg = ansi_col[n - 30];
429 					tcp->cur_attr = mask2attr(tcp);
430 					break;
431 				case 39: /* restore fg color back to normal */
432 					tcp->attr_mask &= ~(FG_CHANGED|BOLD_ATTR);
433 					tcp->cur_color.fg = tcp->std_color.fg;
434 					tcp->cur_attr = mask2attr(tcp);
435 					break;
436 				case 40: case 41: /* set ansi bg color */
437 				case 42: case 43: case 44:
438 				case 45: case 46: case 47:
439 					tcp->attr_mask |= BG_CHANGED;
440 					tcp->cur_color.bg = ansi_col[n - 40];
441 					tcp->cur_attr = mask2attr(tcp);
442 		    			break;
443 				case 49: /* restore bg color back to normal */
444 					tcp->attr_mask &= ~BG_CHANGED;
445 					tcp->cur_color.bg = tcp->std_color.bg;
446 					tcp->cur_attr = mask2attr(tcp);
447 					break;
448 				}
449 			}
450 			break;
451 
452 		case 's':	/* Save cursor position */
453 			tcp->saved_xpos = scp->xpos;
454 			tcp->saved_ypos = scp->ypos;
455 			break;
456 
457 		case 'u':	/* Restore saved cursor position */
458 			if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
459 				sc_move_cursor(scp, tcp->saved_xpos,
460 					       tcp->saved_ypos);
461 			break;
462 
463 		case 'x':
464 			if (tcp->num_param == 0)
465 				n = 0;
466 			else
467 				n = tcp->param[0];
468 			switch (n) {
469 			case 0: /* reset colors and attributes back to normal */
470 				tcp->attr_mask = NORMAL_ATTR;
471 				tcp->cur_color = tcp->std_color
472 					       = tcp->dflt_std_color;
473 				tcp->rev_color = tcp->dflt_rev_color;
474 				tcp->cur_attr = mask2attr(tcp);
475 				break;
476 			case 1:	/* set ansi background */
477 				tcp->attr_mask &= ~BG_CHANGED;
478 				tcp->cur_color.bg = tcp->std_color.bg
479 						  = ansi_col[tcp->param[1] & 0x0f];
480 				tcp->cur_attr = mask2attr(tcp);
481 				break;
482 			case 2:	/* set ansi foreground */
483 				tcp->attr_mask &= ~FG_CHANGED;
484 				tcp->cur_color.fg = tcp->std_color.fg
485 						  = ansi_col[tcp->param[1] & 0x0f];
486 				tcp->cur_attr = mask2attr(tcp);
487 				break;
488 			case 3: /* set adapter attribute directly */
489 				tcp->attr_mask &= ~(FG_CHANGED | BG_CHANGED);
490 				tcp->cur_color.fg = tcp->std_color.fg
491 						  = tcp->param[1] & 0x0f;
492 				tcp->cur_color.bg = tcp->std_color.bg
493 						  = (tcp->param[1] >> 4) & 0x0f;
494 				tcp->cur_attr = mask2attr(tcp);
495 				break;
496 			case 5: /* set ansi reverse background */
497 				tcp->rev_color.bg = ansi_col[tcp->param[1] & 0x0f];
498 				tcp->cur_attr = mask2attr(tcp);
499 				break;
500 			case 6: /* set ansi reverse foreground */
501 				tcp->rev_color.fg = ansi_col[tcp->param[1] & 0x0f];
502 				tcp->cur_attr = mask2attr(tcp);
503 				break;
504 			case 7: /* set adapter reverse attribute directly */
505 				tcp->rev_color.fg = tcp->param[1] & 0x0f;
506 				tcp->rev_color.bg = (tcp->param[1] >> 4) & 0x0f;
507 				tcp->cur_attr = mask2attr(tcp);
508 				break;
509 			}
510 			break;
511 
512 		case 'z':	/* switch to (virtual) console n */
513 			if (tcp->num_param == 1)
514 				sc_switch_scr(sc, tcp->param[0]);
515 			break;
516 		}
517 	} else if (tcp->esc == 3) {	/* seen ESC [0-9]+ = */
518 		if (c >= '0' && c <= '9') {
519 			if (tcp->num_param < MAX_ESC_PAR) {
520 				if (tcp->last_param != tcp->num_param) {
521 					tcp->last_param = tcp->num_param;
522 					tcp->param[tcp->num_param] = 0;
523 				} else {
524 					tcp->param[tcp->num_param] *= 10;
525 				}
526 				tcp->param[tcp->num_param] += c - '0';
527 				return;
528 			}
529 		}
530 		tcp->num_param = tcp->last_param + 1;
531 		switch (c) {
532 
533 		case ';':
534 			if (tcp->num_param < MAX_ESC_PAR)
535 				return;
536 			break;
537 
538 		case 'A':   /* set display border color */
539 			if (tcp->num_param == 1) {
540 				scp->border=tcp->param[0] & 0xff;
541 				if (scp == sc->cur_scp)
542 					sc_set_border(scp, scp->border);
543 			}
544 			break;
545 
546 		case 'B':   /* set bell pitch and duration */
547 			if (tcp->num_param == 2) {
548 				scp->bell_pitch = tcp->param[0];
549 				scp->bell_duration =
550 				    (tcp->param[1] * hz + 99) / 100;
551 			}
552 			break;
553 
554 		case 'C':   /* set cursor type & shape */
555 			crit_enter();
556 			if (!ISGRAPHSC(sc->cur_scp))
557 				sc_remove_cursor_image(sc->cur_scp);
558 			if (tcp->num_param == 1) {
559 				if (tcp->param[0] & 0x01)
560 					sc->flags |= SC_BLINK_CURSOR;
561 				else
562 					sc->flags &= ~SC_BLINK_CURSOR;
563 				if (tcp->param[0] & 0x02)
564 					sc->flags |= SC_CHAR_CURSOR;
565 				else
566 					sc->flags &= ~SC_CHAR_CURSOR;
567 			} else if (tcp->num_param == 2) {
568 				sc->cursor_base = scp->font_size
569 						- (tcp->param[1] & 0x1F) - 1;
570 				sc->cursor_height = (tcp->param[1] & 0x1F)
571 						- (tcp->param[0] & 0x1F) + 1;
572 			}
573 			/*
574 			 * The cursor shape is global property;
575 			 * all virtual consoles are affected.
576 			 * Update the cursor in the current console...
577 			 */
578 			if (!ISGRAPHSC(sc->cur_scp)) {
579 				sc_set_cursor_image(sc->cur_scp);
580 				sc_draw_cursor_image(sc->cur_scp);
581 			}
582 			crit_exit();
583 			break;
584 
585 		case 'F':   /* set adapter foreground */
586 			if (tcp->num_param == 1) {
587 				tcp->attr_mask &= ~FG_CHANGED;
588 				tcp->cur_color.fg = tcp->std_color.fg
589 						  = tcp->param[0] & 0x0f;
590 				tcp->cur_attr = mask2attr(tcp);
591 			}
592 			break;
593 
594 		case 'G':   /* set adapter background */
595 			if (tcp->num_param == 1) {
596 				tcp->attr_mask &= ~BG_CHANGED;
597 				tcp->cur_color.bg = tcp->std_color.bg
598 						  = tcp->param[0] & 0x0f;
599 				tcp->cur_attr = mask2attr(tcp);
600 			}
601 			break;
602 
603 		case 'H':   /* set adapter reverse foreground */
604 			if (tcp->num_param == 1) {
605 				tcp->rev_color.fg = tcp->param[0] & 0x0f;
606 				tcp->cur_attr = mask2attr(tcp);
607 			}
608 			break;
609 
610 		case 'I':   /* set adapter reverse background */
611 			if (tcp->num_param == 1) {
612 				tcp->rev_color.bg = tcp->param[0] & 0x0f;
613 				tcp->cur_attr = mask2attr(tcp);
614 			}
615 			break;
616 		}
617 #if notyet
618 	} else if (tcp->esc == 4) {	/* seen ESC Q */
619 		/* to be filled */
620 #endif
621 	} else if (tcp->esc == 5) {	/* seen ESC ( */
622 		switch (c) {
623 		case 'B':   /* iso-2022: desginate ASCII into G0 */
624 			break;
625 		/* other items to be filled */
626 		default:
627 			break;
628 		}
629 	}
630 	tcp->esc = 0;
631 }
632 
633 static void
634 scterm_puts(scr_stat *scp, u_char *buf, int len)
635 {
636 	term_stat *tcp;
637 
638 	tcp = scp->ts;
639 outloop:
640 	scp->sc->write_in_progress++;
641 
642 	if (tcp->esc) {
643 		scterm_scan_esc(scp, tcp, *buf);
644 		buf++;
645 		len--;
646 	} else {
647 		switch (*buf) {
648 		case 0x1b:
649 			tcp->esc = 1;
650 			tcp->num_param = 0;
651 			buf++;
652 			len--;
653 			break;
654 		default:
655 			sc_term_gen_print(scp, &buf, &len, tcp->cur_attr);
656 			break;
657 		}
658 	}
659 
660 	sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
661 
662 	scp->sc->write_in_progress--;
663 	if (len)
664 		goto outloop;
665 }
666 
667 static int
668 scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
669 	     int flag)
670 {
671 	term_stat *tcp = scp->ts;
672 	vid_info_t *vi;
673 
674 	switch (cmd) {
675 	case GIO_ATTR:      	/* get current attributes */
676 		/* FIXME: */
677 		*(int*)data = (tcp->cur_attr >> 8) & 0xff;
678 		return 0;
679 	case CONS_GETINFO:  	/* get current (virtual) console info */
680 		vi = (vid_info_t *)data;
681 		if (vi->size != sizeof(struct vid_info))
682 			return EINVAL;
683 		vi->mv_norm.fore = tcp->std_color.fg;
684 		vi->mv_norm.back = tcp->std_color.bg;
685 		vi->mv_rev.fore = tcp->rev_color.fg;
686 		vi->mv_rev.back = tcp->rev_color.bg;
687 		/*
688 		 * The other fields are filled by the upper routine. XXX
689 		 */
690 		return ENOIOCTL;
691 	}
692 	return ENOIOCTL;
693 }
694 
695 static int
696 scterm_reset(scr_stat *scp, int code)
697 {
698 	/* FIXME */
699 	return 0;
700 }
701 
702 static void
703 scterm_default_attr(scr_stat *scp, int color, int rev_color)
704 {
705 	term_stat *tcp = scp->ts;
706 
707 	tcp->dflt_std_color.fg = color & 0x0f;
708 	tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
709 	tcp->dflt_rev_color.fg = rev_color & 0x0f;
710 	tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
711 	tcp->std_color = tcp->dflt_std_color;
712 	tcp->rev_color = tcp->dflt_rev_color;
713 	tcp->cur_color = tcp->std_color;
714 	tcp->cur_attr = mask2attr(tcp);
715 }
716 
717 static void
718 scterm_clear(scr_stat *scp)
719 {
720 	term_stat *tcp = scp->ts;
721 
722 	sc_move_cursor(scp, 0, 0);
723 	sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
724 	mark_all(scp);
725 }
726 
727 static void
728 scterm_notify(scr_stat *scp, int event)
729 {
730 	switch (event) {
731 	case SC_TE_NOTIFY_VTSWITCH_IN:
732 		break;
733 	case SC_TE_NOTIFY_VTSWITCH_OUT:
734 		break;
735 	}
736 }
737 
738 static int
739 scterm_input(scr_stat *scp, int c, struct tty *tp)
740 {
741 	return FALSE;
742 }
743 
744 /*
745  * Calculate hardware attributes word using logical attributes mask and
746  * hardware colors
747  */
748 
749 /* FIXME */
750 static int
751 mask2attr(term_stat *tcp)
752 {
753 	int attr, mask = tcp->attr_mask;
754 
755 	if (mask & REVERSE_ATTR) {
756 		attr = ((mask & FG_CHANGED) ?
757 			tcp->cur_color.bg : tcp->rev_color.fg) |
758 			(((mask & BG_CHANGED) ?
759 			tcp->cur_color.fg : tcp->rev_color.bg) << 4);
760 	} else
761 		attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
762 
763 	/* XXX: underline mapping for Hercules adapter can be better */
764 	if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
765 		attr ^= 0x08;
766 	if (mask & BLINK_ATTR)
767 		attr ^= 0x80;
768 
769 	return (attr << 8);
770 }
771 
772 #endif /* SC_DUMB_TERMINAL */
773