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: stable/11/sys/pc98/cbus/scterm-sck.c 332815 2018-04-20 12:40:05Z nyan $"); 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 */ 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; 107static sc_term_fkeystr_t scterm_fkeystr; 108 109static 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 128SCTERM_MODULE(sc, sc_term_sc); 129 130static term_stat reserved_term_stat; 131static int default_kanji = UJIS; 132static void scterm_scan_esc(scr_stat *scp, term_stat *tcp, 133 u_char c); 134static int mask2attr(term_stat *tcp); 135 136#ifdef KANJI 137static inline u_char 138iskanji1(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 190static inline u_char 191iskanji2(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 */ 249static 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 256static u_short 257kanji_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 304static int 305scterm_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 356static int 357scterm_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 367static void 368scterm_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 912static void 913scterm_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; 923outloop: 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; 1002kanji_end: 1003 ++ptr; 1004 --len; 1005ascii_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 1112static int 1113scterm_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 1140static int 1141scterm_reset(scr_stat *scp, int code) 1142{ 1143 /* FIXME */ 1144 return 0; 1145} 1146 1147static void 1148scterm_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 1162static void 1163scterm_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 1172static void 1173scterm_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 1183static int 1184scterm_input(scr_stat *scp, int c, struct tty *tp) 1185{ 1186 return FALSE; 1187} 1188 1189static const char * 1190scterm_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 */ 1202static int 1203mask2attr(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