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