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