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