128 129 tp.tp_row = scp->ysize; 130 tp.tp_col = scp->xsize; 131 teken_set_winsize(&ts->ts_teken, &tp); 132 133 tp.tp_row = scp->cursor_pos / scp->xsize; 134 tp.tp_col = scp->cursor_pos % scp->xsize; 135 teken_set_cursor(&ts->ts_teken, &tp); 136 break; 137 } 138 139 return (0); 140} 141 142static int 143scteken_term(scr_stat *scp, void **softc) 144{ 145 146 if (*softc == &reserved_teken_stat) { 147 *softc = NULL; 148 reserved_teken_stat.ts_busy = 0; 149 } 150 --sc_term_scteken.te_refcount; 151 152 return (0); 153} 154 155static void 156scteken_puts(scr_stat *scp, u_char *buf, int len, int kernel) 157{ 158 teken_stat *ts = scp->ts; 159 teken_attr_t backup, kattr; 160 161 scp->sc->write_in_progress++; 162 if (kernel) { 163 /* Use special colors for kernel messages. */ 164 backup = *teken_get_curattr(&ts->ts_teken); 165 scteken_revattr(SC_KERNEL_CONS_ATTR, &kattr); 166 teken_set_curattr(&ts->ts_teken, &kattr); 167 teken_input(&ts->ts_teken, buf, len); 168 teken_set_curattr(&ts->ts_teken, &backup); 169 } else { 170 /* Print user messages with regular colors. */ 171 teken_input(&ts->ts_teken, buf, len); 172 } 173 scp->sc->write_in_progress--; 174} 175 176static int 177scteken_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data, 178 struct thread *td) 179{ 180 teken_stat *ts = scp->ts; 181 vid_info_t *vi; 182 unsigned int attr; 183 184 switch (cmd) { 185 case GIO_ATTR: /* get current attributes */ 186 *(int*)data = 187 scteken_attr(teken_get_curattr(&ts->ts_teken)); 188 return (0); 189 case CONS_GETINFO: /* get current (virtual) console info */ 190 vi = (vid_info_t *)data; 191 if (vi->size != sizeof(struct vid_info)) 192 return EINVAL; 193 194 attr = scteken_attr(teken_get_defattr(&ts->ts_teken)); 195 vi->mv_norm.fore = attr & 0x0f; 196 vi->mv_norm.back = (attr >> 4) & 0x0f; 197 vi->mv_rev.fore = vi->mv_norm.back; 198 vi->mv_rev.back = vi->mv_norm.fore; 199 /* 200 * The other fields are filled by the upper routine. XXX 201 */ 202 return (ENOIOCTL); 203 } 204 205 return (ENOIOCTL); 206} 207 208static void 209scteken_default_attr(scr_stat *scp, int color, int rev_color) 210{ 211 teken_stat *ts = scp->ts; 212 teken_attr_t ta; 213 214 scteken_revattr(color, &ta); 215 teken_set_defattr(&ts->ts_teken, &ta); 216} 217 218static void 219scteken_clear(scr_stat *scp) 220{ 221 222 sc_move_cursor(scp, 0, 0); 223 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], SC_NORM_ATTR << 8); 224 mark_all(scp); 225} 226 227static int 228scteken_input(scr_stat *scp, int c, struct tty *tp) 229{ 230 231 return FALSE; 232} 233 234static void 235scteken_nop(void) 236{ 237 238} 239 240/* 241 * libteken routines. 242 */ 243 244static const unsigned char fgcolors_normal[TC_NCOLORS] = { 245 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, 246 FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY, 247}; 248 249static const unsigned char fgcolors_bold[TC_NCOLORS] = { 250 FG_DARKGREY, FG_LIGHTRED, FG_LIGHTGREEN, FG_YELLOW, 251 FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN, FG_WHITE, 252}; 253 254static const unsigned char bgcolors[TC_NCOLORS] = { 255 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, 256 BG_BLUE, BG_MAGENTA, BG_CYAN, BG_LIGHTGREY, 257}; 258 259static void 260scteken_revattr(unsigned char color, teken_attr_t *a) 261{ 262 teken_color_t fg, bg; 263 264 /* 265 * XXX: Reverse conversion of syscons to teken attributes. Not 266 * realiable. Maybe we should turn it into a 1:1 mapping one of 267 * these days? 268 */ 269 270 a->ta_format = 0; 271 a->ta_fgcolor = TC_WHITE; 272 a->ta_bgcolor = TC_BLACK; 273 274#ifdef FG_BLINK 275 if (color & FG_BLINK) { 276 a->ta_format |= TF_BLINK; 277 color &= ~FG_BLINK; 278 } 279#endif /* FG_BLINK */ 280 281 for (fg = 0; fg < TC_NCOLORS; fg++) { 282 for (bg = 0; bg < TC_NCOLORS; bg++) { 283 if ((fgcolors_normal[fg] | bgcolors[bg]) == color) { 284 a->ta_fgcolor = fg; 285 a->ta_bgcolor = bg; 286 return; 287 } 288 289 if ((fgcolors_bold[fg] | bgcolors[bg]) == color) { 290 a->ta_fgcolor = fg; 291 a->ta_bgcolor = bg; 292 a->ta_format |= TF_BOLD; 293 return; 294 } 295 } 296 } 297} 298 299static unsigned int 300scteken_attr(const teken_attr_t *a) 301{ 302 unsigned int attr = 0; 303 teken_color_t fg, bg; 304 305 if (a->ta_format & TF_REVERSE) { 306 fg = a->ta_bgcolor; 307 bg = a->ta_fgcolor; 308 } else { 309 fg = a->ta_fgcolor; 310 bg = a->ta_bgcolor; 311 } 312 if (a->ta_format & TF_BOLD) 313 attr |= fgcolors_bold[fg]; 314 else 315 attr |= fgcolors_normal[fg]; 316 attr |= bgcolors[bg]; 317 318#ifdef FG_UNDERLINE 319 if (a->ta_format & TF_UNDERLINE) 320 attr |= FG_UNDERLINE; 321#endif /* FG_UNDERLINE */ 322#ifdef FG_BLINK 323 if (a->ta_format & TF_BLINK) 324 attr |= FG_BLINK; 325#endif /* FG_BLINK */ 326 327 return (attr); 328} 329 330static void 331scteken_bell(void *arg) 332{ 333 scr_stat *scp = arg; 334 335 sc_bell(scp, scp->bell_pitch, scp->bell_duration); 336} 337 338static void 339scteken_cursor(void *arg, const teken_pos_t *p) 340{ 341 scr_stat *scp = arg; 342 343 sc_move_cursor(scp, p->tp_col, p->tp_row); 344} 345 346#ifdef TEKEN_UTF8 347struct unicp437 { 348 uint16_t unicode_base; 349 uint8_t cp437_base; 350 uint8_t length; 351}; 352 353static const struct unicp437 cp437table[] = { 354 { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, 355 { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, 356 { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, 357 { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, 358 { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, 359 { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, 360 { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, 361 { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, 362 { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, 363 { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, 364 { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, 365 { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, 366 { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, 367 { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, 368 { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, 369 { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, 370 { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, 371 { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, 372 { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, 373 { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, 374 { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, 375 { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, 376 { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, 377 { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, 378 { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, 379 { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, 380 { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, 381 { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, 382 { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, 383 { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, 384 { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, 385 { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, 386 { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, 387 { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, 388 { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, 389 { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, 390 { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, 391 { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, 392 { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, 393 { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, 394 { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, 395 { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, 396 { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, 397 { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, 398 { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, 399 { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, 400 { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, 401 { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, 402 { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, 403 { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, 404 { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, 405 { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, 406 { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, 407 { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, 408 { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, 409 { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, 410 { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, 411 { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, 412 { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, 413 { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, 414 { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, 415 { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, 416 { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, 417 { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, 418 { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, 419 { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, 420 { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, 421 { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, 422 { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, 423 { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, 424 { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, 425 { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, 426 { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, 427 { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, 428 { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, 429 { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, 430 { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, 431 { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, 432 { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, 433 { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, 434 { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, 435 { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, 436 { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, 437 { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x01 }, 438}; 439 440static void 441scteken_get_cp437(teken_char_t *c, int *attr) 442{ 443 int min, mid, max; 444 445 min = 0; 446 max = (sizeof(cp437table) / sizeof(struct unicp437)) - 1; 447 448 if (*c < cp437table[0].unicode_base || 449 *c > cp437table[max].unicode_base + cp437table[max].length) 450 goto bad; 451 452 while (max >= min) { 453 mid = (min + max) / 2; 454 if (*c < cp437table[mid].unicode_base) { 455 max = mid - 1; 456 } else if (*c > cp437table[mid].unicode_base + 457 cp437table[mid].length) { 458 min = mid + 1; 459 } else { 460 *c -= cp437table[mid].unicode_base; 461 *c += cp437table[mid].cp437_base; 462 return; 463 } 464 } 465bad: 466 /* Character not present in CP437. */ 467 *attr = (FG_RED|BG_BLACK) << 8; 468 *c = '?'; 469} 470#endif /* TEKEN_UTF8 */ 471 472static void 473scteken_putchar(void *arg, const teken_pos_t *tp, teken_char_t c, 474 const teken_attr_t *a) 475{ 476 scr_stat *scp = arg; 477 u_char *map; 478 u_char ch; 479 vm_offset_t p; 480 int cursor, attr; 481 482 attr = scteken_attr(a) << 8; 483#ifdef TEKEN_UTF8 484 scteken_get_cp437(&c, &attr); 485#endif /* TEKEN_UTF8 */ 486 ch = c; 487 488 map = scp->sc->scr_map; 489 490 cursor = tp->tp_row * scp->xsize + tp->tp_col; 491 p = sc_vtb_pointer(&scp->vtb, cursor); 492 sc_vtb_putchar(&scp->vtb, p, map[ch], attr); 493 494 mark_for_update(scp, cursor); 495 /* 496 * XXX: Why do we need this? Only marking `cursor' should be 497 * enough. Without this line, we get artifacts. 498 */ 499 mark_for_update(scp, imin(cursor + 1, scp->xsize * scp->ysize - 1)); 500} 501 502static void 503scteken_fill(void *arg, const teken_rect_t *r, teken_char_t c, 504 const teken_attr_t *a) 505{ 506 scr_stat *scp = arg; 507 u_char *map; 508 u_char ch; 509 unsigned int width; 510 int attr, row; 511 512 attr = scteken_attr(a) << 8; 513#ifdef TEKEN_UTF8 514 scteken_get_cp437(&c, &attr); 515#endif /* TEKEN_UTF8 */ 516 ch = c; 517 518 map = scp->sc->scr_map; 519 520 if (r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize) { 521 /* Single contiguous region to fill. */ 522 sc_vtb_erase(&scp->vtb, r->tr_begin.tp_row * scp->xsize, 523 (r->tr_end.tp_row - r->tr_begin.tp_row) * scp->xsize, 524 map[ch], attr); 525 } else { 526 /* Fill display line by line. */ 527 width = r->tr_end.tp_col - r->tr_begin.tp_col; 528 529 for (row = r->tr_begin.tp_row; row < r->tr_end.tp_row; row++) { 530 sc_vtb_erase(&scp->vtb, r->tr_begin.tp_row * 531 scp->xsize + r->tr_begin.tp_col, 532 width, map[ch], attr); 533 } 534 } 535 536 /* Mark begin and end positions to be refreshed. */ 537 mark_for_update(scp, 538 r->tr_begin.tp_row * scp->xsize + r->tr_begin.tp_col); 539 mark_for_update(scp, 540 (r->tr_end.tp_row - 1) * scp->xsize + (r->tr_end.tp_col - 1)); 541 sc_remove_cutmarking(scp); 542} 543 544static void 545scteken_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) 546{ 547 scr_stat *scp = arg; 548 unsigned int width; 549 int src, dst, end; 550 551#ifndef SC_NO_HISTORY 552 /* 553 * We count a line of input as history if we perform a copy of 554 * one whole line upward. In other words: if a line of text gets 555 * overwritten by a rectangle that's right below it. 556 */ 557 if (scp->history != NULL && 558 r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize && 559 r->tr_begin.tp_row == p->tp_row + 1) { 560 sc_hist_save_one_line(scp, p->tp_row); 561 } 562#endif 563 564 if (r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize) { 565 /* Single contiguous region to copy. */ 566 sc_vtb_move(&scp->vtb, r->tr_begin.tp_row * scp->xsize, 567 p->tp_row * scp->xsize, 568 (r->tr_end.tp_row - r->tr_begin.tp_row) * scp->xsize); 569 } else { 570 /* Copy line by line. */ 571 width = r->tr_end.tp_col - r->tr_begin.tp_col; 572 573 if (p->tp_row < r->tr_begin.tp_row) { 574 /* Copy from top to bottom. */ 575 src = r->tr_begin.tp_row * scp->xsize + 576 r->tr_begin.tp_col; 577 end = r->tr_end.tp_row * scp->xsize + 578 r->tr_end.tp_col; 579 dst = p->tp_row * scp->xsize + p->tp_col; 580 581 while (src < end) { 582 sc_vtb_move(&scp->vtb, src, dst, width); 583 584 src += scp->xsize; 585 dst += scp->xsize; 586 } 587 } else { 588 /* Copy from bottom to top. */ 589 src = (r->tr_end.tp_row - 1) * scp->xsize + 590 r->tr_begin.tp_col; 591 end = r->tr_begin.tp_row * scp->xsize + 592 r->tr_begin.tp_col; 593 dst = (p->tp_row + r->tr_end.tp_row - 594 r->tr_begin.tp_row - 1) * scp->xsize + p->tp_col; 595 596 while (src >= end) { 597 sc_vtb_move(&scp->vtb, src, dst, width); 598 599 src -= scp->xsize; 600 dst -= scp->xsize; 601 } 602 } 603 } 604 605 /* Mark begin and end positions to be refreshed. */ 606 mark_for_update(scp, 607 p->tp_row * scp->xsize + p->tp_col); 608 mark_for_update(scp, 609 (p->tp_row + r->tr_end.tp_row - r->tr_begin.tp_row - 1) * 610 scp->xsize + 611 (p->tp_col + r->tr_end.tp_col - r->tr_begin.tp_col - 1)); 612 sc_remove_cutmarking(scp); 613} 614 615static void 616scteken_param(void *arg, int cmd, unsigned int value) 617{ 618 scr_stat *scp = arg; 619 620 switch (cmd) { 621 case TP_SHOWCURSOR: 622 if (value) { 623 sc_change_cursor_shape(scp, 624 CONS_RESET_CURSOR|CONS_LOCAL_CURSOR, -1, -1); 625 } else { 626 sc_change_cursor_shape(scp, 627 CONS_HIDDEN_CURSOR|CONS_LOCAL_CURSOR, -1, -1); 628 } 629 break; 630 case TP_SWITCHVT: 631 sc_switch_scr(scp->sc, value); 632 break; 633 case TP_SETBELLPD: 634 scp->bell_pitch = TP_SETBELLPD_PITCH(value); 635 scp->bell_duration = TP_SETBELLPD_DURATION(value); 636 break; 637 } 638} 639 640static void 641scteken_respond(void *arg, const void *buf, size_t len) 642{ 643 scr_stat *scp = arg; 644 645 sc_respond(scp, buf, len); 646}
| 131 132 tp.tp_row = scp->ysize; 133 tp.tp_col = scp->xsize; 134 teken_set_winsize(&ts->ts_teken, &tp); 135 136 tp.tp_row = scp->cursor_pos / scp->xsize; 137 tp.tp_col = scp->cursor_pos % scp->xsize; 138 teken_set_cursor(&ts->ts_teken, &tp); 139 break; 140 } 141 142 return (0); 143} 144 145static int 146scteken_term(scr_stat *scp, void **softc) 147{ 148 149 if (*softc == &reserved_teken_stat) { 150 *softc = NULL; 151 reserved_teken_stat.ts_busy = 0; 152 } 153 --sc_term_scteken.te_refcount; 154 155 return (0); 156} 157 158static void 159scteken_puts(scr_stat *scp, u_char *buf, int len, int kernel) 160{ 161 teken_stat *ts = scp->ts; 162 teken_attr_t backup, kattr; 163 164 scp->sc->write_in_progress++; 165 if (kernel) { 166 /* Use special colors for kernel messages. */ 167 backup = *teken_get_curattr(&ts->ts_teken); 168 scteken_revattr(SC_KERNEL_CONS_ATTR, &kattr); 169 teken_set_curattr(&ts->ts_teken, &kattr); 170 teken_input(&ts->ts_teken, buf, len); 171 teken_set_curattr(&ts->ts_teken, &backup); 172 } else { 173 /* Print user messages with regular colors. */ 174 teken_input(&ts->ts_teken, buf, len); 175 } 176 scp->sc->write_in_progress--; 177} 178 179static int 180scteken_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data, 181 struct thread *td) 182{ 183 teken_stat *ts = scp->ts; 184 vid_info_t *vi; 185 unsigned int attr; 186 187 switch (cmd) { 188 case GIO_ATTR: /* get current attributes */ 189 *(int*)data = 190 scteken_attr(teken_get_curattr(&ts->ts_teken)); 191 return (0); 192 case CONS_GETINFO: /* get current (virtual) console info */ 193 vi = (vid_info_t *)data; 194 if (vi->size != sizeof(struct vid_info)) 195 return EINVAL; 196 197 attr = scteken_attr(teken_get_defattr(&ts->ts_teken)); 198 vi->mv_norm.fore = attr & 0x0f; 199 vi->mv_norm.back = (attr >> 4) & 0x0f; 200 vi->mv_rev.fore = vi->mv_norm.back; 201 vi->mv_rev.back = vi->mv_norm.fore; 202 /* 203 * The other fields are filled by the upper routine. XXX 204 */ 205 return (ENOIOCTL); 206 } 207 208 return (ENOIOCTL); 209} 210 211static void 212scteken_default_attr(scr_stat *scp, int color, int rev_color) 213{ 214 teken_stat *ts = scp->ts; 215 teken_attr_t ta; 216 217 scteken_revattr(color, &ta); 218 teken_set_defattr(&ts->ts_teken, &ta); 219} 220 221static void 222scteken_clear(scr_stat *scp) 223{ 224 225 sc_move_cursor(scp, 0, 0); 226 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], SC_NORM_ATTR << 8); 227 mark_all(scp); 228} 229 230static int 231scteken_input(scr_stat *scp, int c, struct tty *tp) 232{ 233 234 return FALSE; 235} 236 237static void 238scteken_nop(void) 239{ 240 241} 242 243/* 244 * libteken routines. 245 */ 246 247static const unsigned char fgcolors_normal[TC_NCOLORS] = { 248 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, 249 FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY, 250}; 251 252static const unsigned char fgcolors_bold[TC_NCOLORS] = { 253 FG_DARKGREY, FG_LIGHTRED, FG_LIGHTGREEN, FG_YELLOW, 254 FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN, FG_WHITE, 255}; 256 257static const unsigned char bgcolors[TC_NCOLORS] = { 258 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, 259 BG_BLUE, BG_MAGENTA, BG_CYAN, BG_LIGHTGREY, 260}; 261 262static void 263scteken_revattr(unsigned char color, teken_attr_t *a) 264{ 265 teken_color_t fg, bg; 266 267 /* 268 * XXX: Reverse conversion of syscons to teken attributes. Not 269 * realiable. Maybe we should turn it into a 1:1 mapping one of 270 * these days? 271 */ 272 273 a->ta_format = 0; 274 a->ta_fgcolor = TC_WHITE; 275 a->ta_bgcolor = TC_BLACK; 276 277#ifdef FG_BLINK 278 if (color & FG_BLINK) { 279 a->ta_format |= TF_BLINK; 280 color &= ~FG_BLINK; 281 } 282#endif /* FG_BLINK */ 283 284 for (fg = 0; fg < TC_NCOLORS; fg++) { 285 for (bg = 0; bg < TC_NCOLORS; bg++) { 286 if ((fgcolors_normal[fg] | bgcolors[bg]) == color) { 287 a->ta_fgcolor = fg; 288 a->ta_bgcolor = bg; 289 return; 290 } 291 292 if ((fgcolors_bold[fg] | bgcolors[bg]) == color) { 293 a->ta_fgcolor = fg; 294 a->ta_bgcolor = bg; 295 a->ta_format |= TF_BOLD; 296 return; 297 } 298 } 299 } 300} 301 302static unsigned int 303scteken_attr(const teken_attr_t *a) 304{ 305 unsigned int attr = 0; 306 teken_color_t fg, bg; 307 308 if (a->ta_format & TF_REVERSE) { 309 fg = a->ta_bgcolor; 310 bg = a->ta_fgcolor; 311 } else { 312 fg = a->ta_fgcolor; 313 bg = a->ta_bgcolor; 314 } 315 if (a->ta_format & TF_BOLD) 316 attr |= fgcolors_bold[fg]; 317 else 318 attr |= fgcolors_normal[fg]; 319 attr |= bgcolors[bg]; 320 321#ifdef FG_UNDERLINE 322 if (a->ta_format & TF_UNDERLINE) 323 attr |= FG_UNDERLINE; 324#endif /* FG_UNDERLINE */ 325#ifdef FG_BLINK 326 if (a->ta_format & TF_BLINK) 327 attr |= FG_BLINK; 328#endif /* FG_BLINK */ 329 330 return (attr); 331} 332 333static void 334scteken_bell(void *arg) 335{ 336 scr_stat *scp = arg; 337 338 sc_bell(scp, scp->bell_pitch, scp->bell_duration); 339} 340 341static void 342scteken_cursor(void *arg, const teken_pos_t *p) 343{ 344 scr_stat *scp = arg; 345 346 sc_move_cursor(scp, p->tp_col, p->tp_row); 347} 348 349#ifdef TEKEN_UTF8 350struct unicp437 { 351 uint16_t unicode_base; 352 uint8_t cp437_base; 353 uint8_t length; 354}; 355 356static const struct unicp437 cp437table[] = { 357 { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, 358 { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, 359 { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, 360 { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, 361 { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, 362 { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, 363 { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, 364 { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, 365 { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, 366 { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, 367 { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, 368 { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, 369 { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, 370 { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, 371 { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, 372 { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, 373 { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, 374 { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, 375 { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, 376 { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, 377 { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, 378 { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, 379 { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, 380 { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, 381 { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, 382 { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, 383 { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, 384 { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, 385 { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, 386 { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, 387 { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, 388 { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, 389 { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, 390 { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, 391 { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, 392 { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, 393 { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, 394 { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, 395 { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, 396 { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, 397 { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, 398 { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, 399 { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, 400 { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, 401 { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, 402 { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, 403 { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, 404 { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, 405 { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, 406 { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, 407 { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, 408 { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, 409 { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, 410 { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, 411 { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, 412 { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, 413 { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, 414 { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, 415 { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, 416 { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, 417 { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, 418 { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, 419 { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, 420 { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, 421 { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, 422 { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, 423 { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, 424 { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, 425 { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, 426 { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, 427 { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, 428 { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, 429 { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, 430 { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, 431 { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, 432 { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, 433 { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, 434 { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, 435 { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, 436 { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, 437 { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, 438 { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, 439 { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, 440 { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x01 }, 441}; 442 443static void 444scteken_get_cp437(teken_char_t *c, int *attr) 445{ 446 int min, mid, max; 447 448 min = 0; 449 max = (sizeof(cp437table) / sizeof(struct unicp437)) - 1; 450 451 if (*c < cp437table[0].unicode_base || 452 *c > cp437table[max].unicode_base + cp437table[max].length) 453 goto bad; 454 455 while (max >= min) { 456 mid = (min + max) / 2; 457 if (*c < cp437table[mid].unicode_base) { 458 max = mid - 1; 459 } else if (*c > cp437table[mid].unicode_base + 460 cp437table[mid].length) { 461 min = mid + 1; 462 } else { 463 *c -= cp437table[mid].unicode_base; 464 *c += cp437table[mid].cp437_base; 465 return; 466 } 467 } 468bad: 469 /* Character not present in CP437. */ 470 *attr = (FG_RED|BG_BLACK) << 8; 471 *c = '?'; 472} 473#endif /* TEKEN_UTF8 */ 474 475static void 476scteken_putchar(void *arg, const teken_pos_t *tp, teken_char_t c, 477 const teken_attr_t *a) 478{ 479 scr_stat *scp = arg; 480 u_char *map; 481 u_char ch; 482 vm_offset_t p; 483 int cursor, attr; 484 485 attr = scteken_attr(a) << 8; 486#ifdef TEKEN_UTF8 487 scteken_get_cp437(&c, &attr); 488#endif /* TEKEN_UTF8 */ 489 ch = c; 490 491 map = scp->sc->scr_map; 492 493 cursor = tp->tp_row * scp->xsize + tp->tp_col; 494 p = sc_vtb_pointer(&scp->vtb, cursor); 495 sc_vtb_putchar(&scp->vtb, p, map[ch], attr); 496 497 mark_for_update(scp, cursor); 498 /* 499 * XXX: Why do we need this? Only marking `cursor' should be 500 * enough. Without this line, we get artifacts. 501 */ 502 mark_for_update(scp, imin(cursor + 1, scp->xsize * scp->ysize - 1)); 503} 504 505static void 506scteken_fill(void *arg, const teken_rect_t *r, teken_char_t c, 507 const teken_attr_t *a) 508{ 509 scr_stat *scp = arg; 510 u_char *map; 511 u_char ch; 512 unsigned int width; 513 int attr, row; 514 515 attr = scteken_attr(a) << 8; 516#ifdef TEKEN_UTF8 517 scteken_get_cp437(&c, &attr); 518#endif /* TEKEN_UTF8 */ 519 ch = c; 520 521 map = scp->sc->scr_map; 522 523 if (r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize) { 524 /* Single contiguous region to fill. */ 525 sc_vtb_erase(&scp->vtb, r->tr_begin.tp_row * scp->xsize, 526 (r->tr_end.tp_row - r->tr_begin.tp_row) * scp->xsize, 527 map[ch], attr); 528 } else { 529 /* Fill display line by line. */ 530 width = r->tr_end.tp_col - r->tr_begin.tp_col; 531 532 for (row = r->tr_begin.tp_row; row < r->tr_end.tp_row; row++) { 533 sc_vtb_erase(&scp->vtb, r->tr_begin.tp_row * 534 scp->xsize + r->tr_begin.tp_col, 535 width, map[ch], attr); 536 } 537 } 538 539 /* Mark begin and end positions to be refreshed. */ 540 mark_for_update(scp, 541 r->tr_begin.tp_row * scp->xsize + r->tr_begin.tp_col); 542 mark_for_update(scp, 543 (r->tr_end.tp_row - 1) * scp->xsize + (r->tr_end.tp_col - 1)); 544 sc_remove_cutmarking(scp); 545} 546 547static void 548scteken_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) 549{ 550 scr_stat *scp = arg; 551 unsigned int width; 552 int src, dst, end; 553 554#ifndef SC_NO_HISTORY 555 /* 556 * We count a line of input as history if we perform a copy of 557 * one whole line upward. In other words: if a line of text gets 558 * overwritten by a rectangle that's right below it. 559 */ 560 if (scp->history != NULL && 561 r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize && 562 r->tr_begin.tp_row == p->tp_row + 1) { 563 sc_hist_save_one_line(scp, p->tp_row); 564 } 565#endif 566 567 if (r->tr_begin.tp_col == 0 && r->tr_end.tp_col == scp->xsize) { 568 /* Single contiguous region to copy. */ 569 sc_vtb_move(&scp->vtb, r->tr_begin.tp_row * scp->xsize, 570 p->tp_row * scp->xsize, 571 (r->tr_end.tp_row - r->tr_begin.tp_row) * scp->xsize); 572 } else { 573 /* Copy line by line. */ 574 width = r->tr_end.tp_col - r->tr_begin.tp_col; 575 576 if (p->tp_row < r->tr_begin.tp_row) { 577 /* Copy from top to bottom. */ 578 src = r->tr_begin.tp_row * scp->xsize + 579 r->tr_begin.tp_col; 580 end = r->tr_end.tp_row * scp->xsize + 581 r->tr_end.tp_col; 582 dst = p->tp_row * scp->xsize + p->tp_col; 583 584 while (src < end) { 585 sc_vtb_move(&scp->vtb, src, dst, width); 586 587 src += scp->xsize; 588 dst += scp->xsize; 589 } 590 } else { 591 /* Copy from bottom to top. */ 592 src = (r->tr_end.tp_row - 1) * scp->xsize + 593 r->tr_begin.tp_col; 594 end = r->tr_begin.tp_row * scp->xsize + 595 r->tr_begin.tp_col; 596 dst = (p->tp_row + r->tr_end.tp_row - 597 r->tr_begin.tp_row - 1) * scp->xsize + p->tp_col; 598 599 while (src >= end) { 600 sc_vtb_move(&scp->vtb, src, dst, width); 601 602 src -= scp->xsize; 603 dst -= scp->xsize; 604 } 605 } 606 } 607 608 /* Mark begin and end positions to be refreshed. */ 609 mark_for_update(scp, 610 p->tp_row * scp->xsize + p->tp_col); 611 mark_for_update(scp, 612 (p->tp_row + r->tr_end.tp_row - r->tr_begin.tp_row - 1) * 613 scp->xsize + 614 (p->tp_col + r->tr_end.tp_col - r->tr_begin.tp_col - 1)); 615 sc_remove_cutmarking(scp); 616} 617 618static void 619scteken_param(void *arg, int cmd, unsigned int value) 620{ 621 scr_stat *scp = arg; 622 623 switch (cmd) { 624 case TP_SHOWCURSOR: 625 if (value) { 626 sc_change_cursor_shape(scp, 627 CONS_RESET_CURSOR|CONS_LOCAL_CURSOR, -1, -1); 628 } else { 629 sc_change_cursor_shape(scp, 630 CONS_HIDDEN_CURSOR|CONS_LOCAL_CURSOR, -1, -1); 631 } 632 break; 633 case TP_SWITCHVT: 634 sc_switch_scr(scp->sc, value); 635 break; 636 case TP_SETBELLPD: 637 scp->bell_pitch = TP_SETBELLPD_PITCH(value); 638 scp->bell_duration = TP_SETBELLPD_DURATION(value); 639 break; 640 } 641} 642 643static void 644scteken_respond(void *arg, const void *buf, size_t len) 645{ 646 scr_stat *scp = arg; 647 648 sc_respond(scp, buf, len); 649}
|