2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3 * Copyright (c) 1992-1998 Søren Schmidt
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
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.7 2006/07/28 02:17:36 dillon Exp $
31 #include "opt_syscons.h"
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>
39 #include <machine/pc/display.h>
42 #include "sctermvar.h"
44 #ifndef SC_DUMB_TERMINAL
50 u_short fg; /* foreground color */
51 u_short bg; /* background color */
56 #define SCTERM_BUSY (1 << 0)
60 int param[MAX_ESC_PAR];
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 */
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;
89 static sc_term_sw_t sc_term_sc = {
91 "sc", /* emulator name */
92 "syscons terminal", /* description */
93 "*", /* matching renderer, any :-) */
94 sizeof(term_stat), /* softc size */
107 SCTERM_MODULE(sc, sc_term_sc);
109 static term_stat reserved_term_stat;
110 static void scterm_scan_esc(scr_stat *scp, term_stat *tcp,
112 static int mask2attr(term_stat *tcp);
115 scterm_init(scr_stat *scp, void **softc, int code)
119 if (*softc == NULL) {
120 if (reserved_term_stat.flags & SCTERM_BUSY)
122 *softc = &reserved_term_stat;
127 case SC_TE_COLD_INIT:
128 bzero(tcp, sizeof(*tcp));
129 tcp->flags = SCTERM_BUSY;
131 tcp->saved_xpos = -1;
132 tcp->saved_ypos = -1;
133 tcp->attr_mask = NORMAL_ATTR;
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;
146 case SC_TE_WARM_INIT:
148 tcp->saved_xpos = -1;
149 tcp->saved_ypos = -1;
151 tcp->std_color = tcp->dflt_std_color;
152 tcp->rev_color = tcp->dflt_rev_color;
154 tcp->cur_color = tcp->std_color;
155 tcp->cur_attr = mask2attr(tcp);
163 scterm_term(scr_stat *scp, void **softc)
165 if (*softc == &reserved_term_stat) {
167 bzero(&reserved_term_stat, sizeof(reserved_term_stat));
169 --sc_term_sc.te_refcount;
174 scterm_scan_esc(scr_stat *scp, term_stat *tcp, u_char c)
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
187 if (tcp->esc == 1) { /* seen ESC */
190 case '7': /* Save cursor position */
191 tcp->saved_xpos = scp->xpos;
192 tcp->saved_ypos = scp->ypos;
195 case '8': /* Restore saved cursor position */
196 if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
197 sc_move_cursor(scp, tcp->saved_xpos,
201 case '[': /* Start ESC [ sequence */
203 tcp->last_param = -1;
204 for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
209 case 'M': /* Move cursor up 1 line, scroll if at top */
210 sc_term_up_scroll(scp, 1, sc->scr_map[0x20],
211 tcp->cur_attr, 0, 0);
218 case 'c': /* reset */
219 tcp->attr_mask = NORMAL_ATTR;
220 tcp->cur_color = tcp->std_color
221 = tcp->dflt_std_color;
222 tcp->rev_color = tcp->dflt_rev_color;
223 tcp->cur_attr = mask2attr(tcp);
224 sc_clear_screen(scp);
227 case '(': /* iso-2022: designate 94 character set to G0 */
231 } else if (tcp->esc == 2) { /* seen ESC [ */
232 if (c >= '0' && c <= '9') {
233 if (tcp->num_param < MAX_ESC_PAR) {
234 if (tcp->last_param != tcp->num_param) {
235 tcp->last_param = tcp->num_param;
236 tcp->param[tcp->num_param] = 0;
238 tcp->param[tcp->num_param] *= 10;
240 tcp->param[tcp->num_param] += c - '0';
244 tcp->num_param = tcp->last_param + 1;
248 if (tcp->num_param < MAX_ESC_PAR)
254 tcp->last_param = -1;
255 for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
260 case 'A': /* up n rows */
261 sc_term_up(scp, tcp->param[0], 0);
264 case 'B': /* down n rows */
265 sc_term_down(scp, tcp->param[0], 0);
268 case 'C': /* right n columns */
269 sc_term_right(scp, tcp->param[0]);
272 case 'D': /* left n columns */
273 sc_term_left(scp, tcp->param[0]);
276 case 'E': /* cursor to start of line n lines down */
280 sc_move_cursor(scp, 0, scp->ypos + n);
283 case 'F': /* cursor to start of line n lines up */
287 sc_move_cursor(scp, 0, scp->ypos - n);
290 case 'f': /* Cursor move */
292 if (tcp->num_param == 0)
293 sc_move_cursor(scp, 0, 0);
294 else if (tcp->num_param == 2)
295 sc_move_cursor(scp, tcp->param[1] - 1,
299 case 'J': /* Clear all or part of display */
300 if (tcp->num_param == 0)
304 sc_term_clr_eos(scp, n, sc->scr_map[0x20],
308 case 'K': /* Clear all or part of line */
309 if (tcp->num_param == 0)
313 sc_term_clr_eol(scp, n, sc->scr_map[0x20],
317 case 'L': /* Insert n lines */
318 sc_term_ins_line(scp, scp->ypos, tcp->param[0],
319 sc->scr_map[0x20], tcp->cur_attr, 0);
322 case 'M': /* Delete n lines */
323 sc_term_del_line(scp, scp->ypos, tcp->param[0],
324 sc->scr_map[0x20], tcp->cur_attr, 0);
327 case 'P': /* Delete n chars */
328 sc_term_del_char(scp, tcp->param[0],
329 sc->scr_map[0x20], tcp->cur_attr);
332 case '@': /* Insert n chars */
333 sc_term_ins_char(scp, tcp->param[0],
334 sc->scr_map[0x20], tcp->cur_attr);
337 case 'S': /* scroll up n lines */
338 sc_term_del_line(scp, 0, tcp->param[0],
339 sc->scr_map[0x20], tcp->cur_attr, 0);
342 case 'T': /* scroll down n lines */
343 sc_term_ins_line(scp, 0, tcp->param[0],
344 sc->scr_map[0x20], tcp->cur_attr, 0);
347 case 'X': /* erase n characters in line */
351 if (n > scp->xsize - scp->xpos)
352 n = scp->xsize - scp->xpos;
353 sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
354 sc->scr_map[0x20], tcp->cur_attr);
355 mark_for_update(scp, scp->cursor_pos);
356 mark_for_update(scp, scp->cursor_pos + n - 1);
359 case 'Z': /* move n tabs backwards */
360 sc_term_backtab(scp, tcp->param[0]);
363 case '`': /* move cursor to column n */
364 sc_term_col(scp, tcp->param[0]);
367 case 'a': /* move cursor n columns to the right */
368 sc_term_right(scp, tcp->param[0]);
371 case 'd': /* move cursor to row n */
372 sc_term_row(scp, tcp->param[0]);
375 case 'e': /* move cursor n rows down */
376 sc_term_down(scp, tcp->param[0], 0);
379 case 'm': /* change attribute */
380 if (tcp->num_param == 0) {
381 tcp->attr_mask = NORMAL_ATTR;
382 tcp->cur_color = tcp->std_color;
383 tcp->cur_attr = mask2attr(tcp);
386 for (i = 0; i < tcp->num_param; i++) {
387 switch (n = tcp->param[i]) {
388 case 0: /* back to normal */
389 tcp->attr_mask = NORMAL_ATTR;
390 tcp->cur_color = tcp->std_color;
391 tcp->cur_attr = mask2attr(tcp);
394 tcp->attr_mask |= BOLD_ATTR;
395 tcp->cur_attr = mask2attr(tcp);
397 case 4: /* underline */
398 tcp->attr_mask |= UNDERLINE_ATTR;
399 tcp->cur_attr = mask2attr(tcp);
402 tcp->attr_mask |= BLINK_ATTR;
403 tcp->cur_attr = mask2attr(tcp);
405 case 7: /* reverse */
406 tcp->attr_mask |= REVERSE_ATTR;
407 tcp->cur_attr = mask2attr(tcp);
409 case 22: /* remove bold (or dim) */
410 tcp->attr_mask &= ~BOLD_ATTR;
411 tcp->cur_attr = mask2attr(tcp);
413 case 24: /* remove underline */
414 tcp->attr_mask &= ~UNDERLINE_ATTR;
415 tcp->cur_attr = mask2attr(tcp);
417 case 25: /* remove blink */
418 tcp->attr_mask &= ~BLINK_ATTR;
419 tcp->cur_attr = mask2attr(tcp);
421 case 27: /* remove reverse */
422 tcp->attr_mask &= ~REVERSE_ATTR;
423 tcp->cur_attr = mask2attr(tcp);
425 case 30: case 31: /* set ansi fg color */
426 case 32: case 33: case 34:
427 case 35: case 36: case 37:
428 tcp->attr_mask |= FG_CHANGED;
429 tcp->cur_color.fg = ansi_col[n - 30];
430 tcp->cur_attr = mask2attr(tcp);
432 case 39: /* restore fg color back to normal */
433 tcp->attr_mask &= ~(FG_CHANGED|BOLD_ATTR);
434 tcp->cur_color.fg = tcp->std_color.fg;
435 tcp->cur_attr = mask2attr(tcp);
437 case 40: case 41: /* set ansi bg color */
438 case 42: case 43: case 44:
439 case 45: case 46: case 47:
440 tcp->attr_mask |= BG_CHANGED;
441 tcp->cur_color.bg = ansi_col[n - 40];
442 tcp->cur_attr = mask2attr(tcp);
444 case 49: /* restore bg color back to normal */
445 tcp->attr_mask &= ~BG_CHANGED;
446 tcp->cur_color.bg = tcp->std_color.bg;
447 tcp->cur_attr = mask2attr(tcp);
453 case 's': /* Save cursor position */
454 tcp->saved_xpos = scp->xpos;
455 tcp->saved_ypos = scp->ypos;
458 case 'u': /* Restore saved cursor position */
459 if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
460 sc_move_cursor(scp, tcp->saved_xpos,
465 if (tcp->num_param == 0)
470 case 0: /* reset colors and attributes back to normal */
471 tcp->attr_mask = NORMAL_ATTR;
472 tcp->cur_color = tcp->std_color
473 = tcp->dflt_std_color;
474 tcp->rev_color = tcp->dflt_rev_color;
475 tcp->cur_attr = mask2attr(tcp);
477 case 1: /* set ansi background */
478 tcp->attr_mask &= ~BG_CHANGED;
479 tcp->cur_color.bg = tcp->std_color.bg
480 = ansi_col[tcp->param[1] & 0x0f];
481 tcp->cur_attr = mask2attr(tcp);
483 case 2: /* set ansi foreground */
484 tcp->attr_mask &= ~FG_CHANGED;
485 tcp->cur_color.fg = tcp->std_color.fg
486 = ansi_col[tcp->param[1] & 0x0f];
487 tcp->cur_attr = mask2attr(tcp);
489 case 3: /* set adapter attribute directly */
490 tcp->attr_mask &= ~(FG_CHANGED | BG_CHANGED);
491 tcp->cur_color.fg = tcp->std_color.fg
492 = tcp->param[1] & 0x0f;
493 tcp->cur_color.bg = tcp->std_color.bg
494 = (tcp->param[1] >> 4) & 0x0f;
495 tcp->cur_attr = mask2attr(tcp);
497 case 5: /* set ansi reverse background */
498 tcp->rev_color.bg = ansi_col[tcp->param[1] & 0x0f];
499 tcp->cur_attr = mask2attr(tcp);
501 case 6: /* set ansi reverse foreground */
502 tcp->rev_color.fg = ansi_col[tcp->param[1] & 0x0f];
503 tcp->cur_attr = mask2attr(tcp);
505 case 7: /* set adapter reverse attribute directly */
506 tcp->rev_color.fg = tcp->param[1] & 0x0f;
507 tcp->rev_color.bg = (tcp->param[1] >> 4) & 0x0f;
508 tcp->cur_attr = mask2attr(tcp);
513 case 'z': /* switch to (virtual) console n */
514 if (tcp->num_param == 1)
515 sc_switch_scr(sc, tcp->param[0]);
518 } else if (tcp->esc == 3) { /* seen ESC [0-9]+ = */
519 if (c >= '0' && c <= '9') {
520 if (tcp->num_param < MAX_ESC_PAR) {
521 if (tcp->last_param != tcp->num_param) {
522 tcp->last_param = tcp->num_param;
523 tcp->param[tcp->num_param] = 0;
525 tcp->param[tcp->num_param] *= 10;
527 tcp->param[tcp->num_param] += c - '0';
531 tcp->num_param = tcp->last_param + 1;
535 if (tcp->num_param < MAX_ESC_PAR)
539 case 'A': /* set display border color */
540 if (tcp->num_param == 1) {
541 scp->border=tcp->param[0] & 0xff;
542 if (scp == sc->cur_scp)
543 sc_set_border(scp, scp->border);
547 case 'B': /* set bell pitch and duration */
548 if (tcp->num_param == 2) {
549 scp->bell_pitch = tcp->param[0];
551 (tcp->param[1] * hz + 99) / 100;
555 case 'C': /* set cursor type & shape */
557 if (!ISGRAPHSC(sc->cur_scp))
558 sc_remove_cursor_image(sc->cur_scp);
559 if (tcp->num_param == 1) {
560 if (tcp->param[0] & 0x01)
561 sc->flags |= SC_BLINK_CURSOR;
563 sc->flags &= ~SC_BLINK_CURSOR;
564 if (tcp->param[0] & 0x02)
565 sc->flags |= SC_CHAR_CURSOR;
567 sc->flags &= ~SC_CHAR_CURSOR;
568 } else if (tcp->num_param == 2) {
569 sc->cursor_base = scp->font_size
570 - (tcp->param[1] & 0x1F) - 1;
571 sc->cursor_height = (tcp->param[1] & 0x1F)
572 - (tcp->param[0] & 0x1F) + 1;
575 * The cursor shape is global property;
576 * all virtual consoles are affected.
577 * Update the cursor in the current console...
579 if (!ISGRAPHSC(sc->cur_scp)) {
580 sc_set_cursor_image(sc->cur_scp);
581 sc_draw_cursor_image(sc->cur_scp);
586 case 'F': /* set adapter foreground */
587 if (tcp->num_param == 1) {
588 tcp->attr_mask &= ~FG_CHANGED;
589 tcp->cur_color.fg = tcp->std_color.fg
590 = tcp->param[0] & 0x0f;
591 tcp->cur_attr = mask2attr(tcp);
595 case 'G': /* set adapter background */
596 if (tcp->num_param == 1) {
597 tcp->attr_mask &= ~BG_CHANGED;
598 tcp->cur_color.bg = tcp->std_color.bg
599 = tcp->param[0] & 0x0f;
600 tcp->cur_attr = mask2attr(tcp);
604 case 'H': /* set adapter reverse foreground */
605 if (tcp->num_param == 1) {
606 tcp->rev_color.fg = tcp->param[0] & 0x0f;
607 tcp->cur_attr = mask2attr(tcp);
611 case 'I': /* set adapter reverse background */
612 if (tcp->num_param == 1) {
613 tcp->rev_color.bg = tcp->param[0] & 0x0f;
614 tcp->cur_attr = mask2attr(tcp);
619 } else if (tcp->esc == 4) { /* seen ESC Q */
622 } else if (tcp->esc == 5) { /* seen ESC ( */
624 case 'B': /* iso-2022: desginate ASCII into G0 */
626 /* other items to be filled */
635 scterm_puts(scr_stat *scp, u_char *buf, int len)
641 scp->sc->write_in_progress++;
644 scterm_scan_esc(scp, tcp, *buf);
656 sc_term_gen_print(scp, &buf, &len, tcp->cur_attr);
661 sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
663 scp->sc->write_in_progress--;
669 scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
672 term_stat *tcp = scp->ts;
676 case GIO_ATTR: /* get current attributes */
678 *(int*)data = (tcp->cur_attr >> 8) & 0xff;
680 case CONS_GETINFO: /* get current (virtual) console info */
681 vi = (vid_info_t *)data;
682 if (vi->size != sizeof(struct vid_info))
684 vi->mv_norm.fore = tcp->std_color.fg;
685 vi->mv_norm.back = tcp->std_color.bg;
686 vi->mv_rev.fore = tcp->rev_color.fg;
687 vi->mv_rev.back = tcp->rev_color.bg;
689 * The other fields are filled by the upper routine. XXX
697 scterm_reset(scr_stat *scp, int code)
704 scterm_default_attr(scr_stat *scp, int color, int rev_color)
706 term_stat *tcp = scp->ts;
708 tcp->dflt_std_color.fg = color & 0x0f;
709 tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
710 tcp->dflt_rev_color.fg = rev_color & 0x0f;
711 tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
712 tcp->std_color = tcp->dflt_std_color;
713 tcp->rev_color = tcp->dflt_rev_color;
714 tcp->cur_color = tcp->std_color;
715 tcp->cur_attr = mask2attr(tcp);
719 scterm_clear(scr_stat *scp)
721 term_stat *tcp = scp->ts;
723 sc_move_cursor(scp, 0, 0);
724 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
729 scterm_notify(scr_stat *scp, int event)
732 case SC_TE_NOTIFY_VTSWITCH_IN:
734 case SC_TE_NOTIFY_VTSWITCH_OUT:
740 scterm_input(scr_stat *scp, int c, struct tty *tp)
746 * Calculate hardware attributes word using logical attributes mask and
752 mask2attr(term_stat *tcp)
754 int attr, mask = tcp->attr_mask;
756 if (mask & REVERSE_ATTR) {
757 attr = ((mask & FG_CHANGED) ?
758 tcp->cur_color.bg : tcp->rev_color.fg) |
759 (((mask & BG_CHANGED) ?
760 tcp->cur_color.fg : tcp->rev_color.bg) << 4);
762 attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
764 /* XXX: underline mapping for Hercules adapter can be better */
765 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
767 if (mask & BLINK_ATTR)
773 #endif /* SC_DUMB_TERMINAL */