1 /* $NetBSD: ite.c,v 1.27 1995/04/10 09:11:41 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: Utah Hdr: ite.c 1.1 90/07/09 41 * @(#)ite.c 7.6 (Berkeley) 5/16/91 42 */ 43 44 /* 45 * ite - bitmaped terminal. 46 * Supports VT200, a few terminal features will be unavailable until 47 * the system actually probes the device (i.e. not after consinit()) 48 */ 49 50 #include <sys/param.h> 51 #include <sys/kernel.h> 52 #include <sys/conf.h> 53 #include <sys/device.h> 54 #include <sys/malloc.h> 55 #include <sys/ioctl.h> 56 #include <sys/tty.h> 57 #include <sys/termios.h> 58 #include <sys/systm.h> 59 #include <sys/proc.h> 60 #include <dev/cons.h> 61 #include <amiga/amiga/kdassert.h> 62 #include <amiga/amiga/color.h> /* DEBUG */ 63 #include <amiga/amiga/device.h> 64 #include <amiga/dev/iteioctl.h> 65 #include <amiga/dev/itevar.h> 66 #include <amiga/dev/kbdmap.h> 67 #include <amiga/dev/grfioctl.h> 68 #include <amiga/dev/grfvar.h> 69 70 71 /* 72 * XXX go ask sys/kern/tty.c:ttselect() 73 */ 74 #include "grf.h" 75 struct tty *ite_tty[NGRF]; 76 77 #define ITEUNIT(dev) (minor(dev)) 78 79 #define SUBR_INIT(ip) (ip)->grf->g_iteinit(ip) 80 #define SUBR_DEINIT(ip) (ip)->grf->g_itedeinit(ip) 81 #define SUBR_PUTC(ip,c,dy,dx,m) (ip)->grf->g_iteputc(ip,c,dy,dx,m) 82 #define SUBR_CURSOR(ip,flg) (ip)->grf->g_itecursor(ip,flg) 83 #define SUBR_CLEAR(ip,sy,sx,h,w) (ip)->grf->g_iteclear(ip,sy,sx,h,w) 84 #define SUBR_SCROLL(ip,sy,sx,count,dir) \ 85 (ip)->grf->g_itescroll(ip,sy,sx,count,dir) 86 87 u_int ite_confunits; /* configured units */ 88 89 int start_repeat_timeo = 30; /* first repeat after x s/100 */ 90 int next_repeat_timeo = 10; /* next repeat after x s/100 */ 91 92 int ite_default_wrap = 1; /* you want vtxxx-nam, binpatch */ 93 94 struct ite_softc con_itesoftc; 95 u_char cons_tabs[MAX_TABS]; 96 97 struct ite_softc *kbd_ite; 98 int kbd_init; 99 100 static char *index __P((const char *, char)); 101 static int inline atoi __P((const char *)); 102 void iteputchar __P((int c, struct ite_softc *ip)); 103 void ite_putstr __P((const char * s, int len, dev_t dev)); 104 void iteattach __P((struct device *, struct device *, void *)); 105 int itematch __P((struct device *, struct cfdata *, void *)); 106 107 struct cfdriver itecd = { 108 NULL, "ite", (cfmatch_t)itematch, iteattach, DV_DULL, 109 sizeof(struct ite_softc), NULL, 0 }; 110 111 int 112 itematch(pdp, cdp, auxp) 113 struct device *pdp; 114 struct cfdata *cdp; 115 void *auxp; 116 { 117 struct grf_softc *gp; 118 int maj; 119 120 gp = auxp; 121 /* 122 * all that our mask allows (more than enough no one 123 * has > 32 monitors for text consoles on one machine) 124 */ 125 if (cdp->cf_unit >= sizeof(ite_confunits) * NBBY) 126 return(0); 127 /* 128 * XXX 129 * normally this would be done in attach, however 130 * during early init we do not have a device pointer 131 * and thus no unit number. 132 */ 133 for(maj = 0; maj < nchrdev; maj++) 134 if (cdevsw[maj].d_open == iteopen) 135 break; 136 gp->g_itedev = makedev(maj, cdp->cf_unit); 137 return(1); 138 } 139 140 void 141 iteattach(pdp, dp, auxp) 142 struct device *pdp, *dp; 143 void *auxp; 144 { 145 extern int hz; 146 struct grf_softc *gp; 147 struct ite_softc *ip; 148 int s; 149 150 gp = (struct grf_softc *)auxp; 151 152 /* 153 * mark unit as attached (XXX see itematch) 154 */ 155 ite_confunits |= 1 << ITEUNIT(gp->g_itedev); 156 157 if (dp) { 158 ip = (struct ite_softc *)dp; 159 160 s = spltty(); 161 if (con_itesoftc.grf != NULL && 162 con_itesoftc.grf->g_unit == gp->g_unit) { 163 /* 164 * console reinit copy params over. 165 * and console always gets keyboard 166 */ 167 bcopy(&con_itesoftc.grf, &ip->grf, 168 (char *)&ip[1] - (char *)&ip->grf); 169 con_itesoftc.grf = NULL; 170 kbd_ite = ip; 171 } 172 ip->grf = gp; 173 splx(s); 174 175 alloc_sicallback(); 176 iteinit(gp->g_itedev); 177 printf(": rows %d cols %d", ip->rows, ip->cols); 178 printf(" repeat at (%d/100)s next at (%d/100)s", 179 start_repeat_timeo, next_repeat_timeo); 180 181 if (kbd_ite == NULL) 182 kbd_ite = ip; 183 if (kbd_ite == ip) 184 printf(" has keyboard"); 185 printf("\n"); 186 } else { 187 if (con_itesoftc.grf != NULL && 188 con_itesoftc.grf->g_conpri > gp->g_conpri) 189 return; 190 con_itesoftc.grf = gp; 191 con_itesoftc.tabs = cons_tabs; 192 } 193 } 194 195 struct ite_softc * 196 getitesp(dev) 197 dev_t dev; 198 { 199 if (amiga_realconfig && con_itesoftc.grf == NULL) 200 return(itecd.cd_devs[ITEUNIT(dev)]); 201 202 if (con_itesoftc.grf == NULL) 203 panic("no ite_softc for console"); 204 return(&con_itesoftc); 205 } 206 207 /* 208 * cons.c entry points into ite device. 209 */ 210 211 /* 212 * Return a priority in consdev->cn_pri field highest wins. This function 213 * is called before any devices have been probed. 214 */ 215 void 216 itecnprobe(cd) 217 struct consdev *cd; 218 { 219 /* 220 * bring graphics layer up. 221 */ 222 config_console(); 223 224 /* 225 * return priority of the best ite (already picked from attach) 226 * or CN_DEAD. 227 */ 228 if (con_itesoftc.grf == NULL) 229 cd->cn_pri = CN_DEAD; 230 else { 231 cd->cn_pri = con_itesoftc.grf->g_conpri; 232 cd->cn_dev = con_itesoftc.grf->g_itedev; 233 } 234 } 235 236 void 237 itecninit(cd) 238 struct consdev *cd; 239 { 240 struct ite_softc *ip; 241 242 ip = getitesp(cd->cn_dev); 243 iteinit(cd->cn_dev); 244 ip->flags |= ITE_ACTIVE | ITE_ISCONS; 245 } 246 247 /* 248 * ite_cnfinish() is called in ite_init() when the device is 249 * being probed in the normal fasion, thus we can finish setting 250 * up this ite now that the system is more functional. 251 */ 252 void 253 ite_cnfinish(ip) 254 struct ite_softc *ip; 255 { 256 static int done; 257 258 if (done) 259 return; 260 done = 1; 261 } 262 263 int 264 itecngetc(dev) 265 dev_t dev; 266 { 267 int c; 268 269 /* XXX this should be moved */ 270 if (!kbd_init) { 271 kbd_init = 1; 272 kbdenable(); 273 } 274 do { 275 c = kbdgetcn(); 276 c = ite_cnfilter(c, ITEFILT_CONSOLE); 277 } while (c == -1); 278 return (c); 279 } 280 281 void 282 itecnputc(dev, c) 283 dev_t dev; 284 int c; 285 { 286 static int paniced; 287 struct ite_softc *ip; 288 char ch; 289 290 ip = getitesp(dev); 291 ch = c; 292 293 if (panicstr && !paniced && 294 (ip->flags & (ITE_ACTIVE | ITE_INGRF)) != ITE_ACTIVE) { 295 (void)ite_on(dev, 3); 296 paniced = 1; 297 } 298 iteputchar(ch, ip); 299 } 300 301 void 302 itecnpollc(dev, on) 303 dev_t dev; 304 int on; 305 { 306 307 } 308 309 /* 310 * standard entry points to the device. 311 */ 312 313 /* 314 * iteinit() is the standard entry point for initialization of 315 * an ite device, it is also called from ite_cninit(). 316 * 317 */ 318 void 319 iteinit(dev) 320 dev_t dev; 321 { 322 struct ite_softc *ip; 323 324 ip = getitesp(dev); 325 if (ip->flags & ITE_INITED) 326 return; 327 bcopy(&ascii_kbdmap, &kbdmap, sizeof(struct kbdmap)); 328 329 ip->cursorx = 0; 330 ip->cursory = 0; 331 SUBR_INIT(ip); 332 SUBR_CURSOR(ip, DRAW_CURSOR); 333 if (ip->tabs == NULL) 334 ip->tabs = malloc(MAX_TABS * sizeof(u_char),M_DEVBUF,M_WAITOK); 335 ite_reset(ip); 336 ip->flags |= ITE_INITED; 337 } 338 339 int 340 iteopen(dev, mode, devtype, p) 341 dev_t dev; 342 int mode, devtype; 343 struct proc *p; 344 { 345 struct ite_softc *ip; 346 struct tty *tp; 347 int error, first, unit; 348 349 unit = ITEUNIT(dev); 350 first = 0; 351 352 if (((1 << unit) & ite_confunits) == 0) 353 return (ENXIO); 354 355 ip = getitesp(dev); 356 357 if (ip->tp == NULL) 358 tp = ite_tty[unit] = ip->tp = ttymalloc(); 359 else 360 tp = ip->tp; 361 if ((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) == (TS_ISOPEN | TS_XCLUDE) 362 && p->p_ucred->cr_uid != 0) 363 return (EBUSY); 364 if ((ip->flags & ITE_ACTIVE) == 0) { 365 error = ite_on(dev, 0); 366 if (error) 367 return (error); 368 first = 1; 369 } 370 tp->t_oproc = itestart; 371 tp->t_param = ite_param; 372 tp->t_dev = dev; 373 if ((tp->t_state & TS_ISOPEN) == 0) { 374 ttychars(tp); 375 tp->t_iflag = TTYDEF_IFLAG; 376 tp->t_oflag = TTYDEF_OFLAG; 377 tp->t_cflag = TTYDEF_CFLAG; 378 tp->t_lflag = TTYDEF_LFLAG; 379 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 380 tp->t_state = TS_WOPEN | TS_CARR_ON; 381 ttsetwater(tp); 382 } 383 error = (*linesw[tp->t_line].l_open) (dev, tp); 384 if (error == 0) { 385 tp->t_winsize.ws_row = ip->rows; 386 tp->t_winsize.ws_col = ip->cols; 387 if (!kbd_init) { 388 kbd_init = 1; 389 kbdenable(); 390 } 391 } else if (first) 392 ite_off(dev, 0); 393 return (error); 394 } 395 396 int 397 iteclose(dev, flag, mode, p) 398 dev_t dev; 399 int flag, mode; 400 struct proc *p; 401 { 402 struct tty *tp; 403 404 tp = getitesp(dev)->tp; 405 406 KDASSERT(tp); 407 (*linesw[tp->t_line].l_close) (tp, flag); 408 ttyclose(tp); 409 ite_off(dev, 0); 410 return (0); 411 } 412 413 int 414 iteread(dev, uio, flag) 415 dev_t dev; 416 struct uio *uio; 417 int flag; 418 { 419 struct tty *tp; 420 421 tp = getitesp(dev)->tp; 422 423 KDASSERT(tp); 424 return ((*linesw[tp->t_line].l_read) (tp, uio, flag)); 425 } 426 427 int 428 itewrite(dev, uio, flag) 429 dev_t dev; 430 struct uio *uio; 431 int flag; 432 { 433 struct tty *tp; 434 435 tp = getitesp(dev)->tp; 436 437 KDASSERT(tp); 438 return ((*linesw[tp->t_line].l_write) (tp, uio, flag)); 439 } 440 441 int 442 itestop(tp, flag) 443 struct tty *tp; 444 int flag; 445 { 446 447 } 448 449 int 450 iteioctl(dev, cmd, addr, flag, p) 451 dev_t dev; 452 u_long cmd; 453 caddr_t addr; 454 int flag; 455 struct proc *p; 456 { 457 struct iterepeat *irp; 458 struct ite_softc *ip; 459 struct tty *tp; 460 int error; 461 462 ip = getitesp(dev); 463 tp = ip->tp; 464 465 KDASSERT(tp); 466 467 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr, flag, p); 468 if (error >= 0) 469 return (error); 470 error = ttioctl(tp, cmd, addr, flag, p); 471 if (error >= 0) 472 return (error); 473 474 switch (cmd) { 475 case ITEIOCSKMAP: 476 if (addr == 0) 477 return(EFAULT); 478 bcopy(addr, &kbdmap, sizeof(struct kbdmap)); 479 return(0); 480 case ITEIOCGKMAP: 481 if (addr == NULL) 482 return(EFAULT); 483 bcopy(&kbdmap, addr, sizeof(struct kbdmap)); 484 return(0); 485 case ITEIOCGREPT: 486 irp = (struct iterepeat *)addr; 487 irp->start = start_repeat_timeo; 488 irp->next = next_repeat_timeo; 489 case ITEIOCSREPT: 490 irp = (struct iterepeat *)addr; 491 if (irp->start < ITEMINREPEAT && irp->next < ITEMINREPEAT) 492 return(EINVAL); 493 start_repeat_timeo = irp->start; 494 next_repeat_timeo = irp->next; 495 return(0); 496 } 497 /* XXX */ 498 if (minor(dev) == 0) { 499 error = ite_grf_ioctl(ip, cmd, addr, flag, p); 500 if (error >= 0) 501 return (error); 502 } 503 return (ENOTTY); 504 } 505 506 void 507 itestart(tp) 508 struct tty *tp; 509 { 510 struct clist *rbp; 511 struct ite_softc *ip; 512 u_char buf[ITEBURST]; 513 int s, len, n; 514 515 ip = getitesp(tp->t_dev); 516 517 KDASSERT(tp); 518 519 s = spltty(); { 520 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 521 goto out; 522 523 tp->t_state |= TS_BUSY; 524 rbp = &tp->t_outq; 525 526 len = q_to_b(rbp, buf, ITEBURST); 527 } splx(s); 528 529 /* Here is a really good place to implement pre/jumpscroll() */ 530 ite_putstr(buf, len, tp->t_dev); 531 532 s = spltty(); { 533 tp->t_state &= ~TS_BUSY; 534 /* we have characters remaining. */ 535 if (rbp->c_cc) { 536 tp->t_state |= TS_TIMEOUT; 537 timeout(ttrstrt, tp, 1); 538 } 539 /* wakeup we are below */ 540 if (rbp->c_cc <= tp->t_lowat) { 541 if (tp->t_state & TS_ASLEEP) { 542 tp->t_state &= ~TS_ASLEEP; 543 wakeup((caddr_t) rbp); 544 } 545 selwakeup(&tp->t_wsel); 546 } 547 out: 548 } splx(s); 549 } 550 551 int 552 ite_on(dev, flag) 553 dev_t dev; 554 int flag; 555 { 556 struct ite_softc *ip; 557 int unit; 558 559 unit = ITEUNIT(dev); 560 if (((1 << unit) & ite_confunits) == 0) 561 return (ENXIO); 562 563 ip = getitesp(dev); 564 565 /* force ite active, overriding graphics mode */ 566 if (flag & 1) { 567 ip->flags |= ITE_ACTIVE; 568 ip->flags &= ~(ITE_INGRF | ITE_INITED); 569 } 570 /* leave graphics mode */ 571 if (flag & 2) { 572 ip->flags &= ~ITE_INGRF; 573 if ((ip->flags & ITE_ACTIVE) == 0) 574 return (0); 575 } 576 ip->flags |= ITE_ACTIVE; 577 if (ip->flags & ITE_INGRF) 578 return (0); 579 iteinit(dev); 580 return (0); 581 } 582 583 int 584 ite_off(dev, flag) 585 dev_t dev; 586 int flag; 587 { 588 struct ite_softc *ip; 589 590 ip = getitesp(dev); 591 if (flag & 2) 592 ip->flags |= ITE_INGRF; 593 if ((ip->flags & ITE_ACTIVE) == 0) 594 return; 595 if ((flag & 1) || 596 (ip->flags & (ITE_INGRF | ITE_ISCONS | ITE_INITED)) == ITE_INITED) 597 SUBR_DEINIT(ip); 598 if ((flag & 2) == 0) /* XXX hmm grfon() I think wants this to go inactive. */ 599 ip->flags &= ~ITE_ACTIVE; 600 } 601 602 /* XXX called after changes made in underlying grf layer. */ 603 /* I want to nuke this */ 604 void 605 ite_reinit(dev) 606 dev_t dev; 607 { 608 struct ite_softc *ip; 609 610 ip = getitesp(dev); 611 ip->flags &= ~ITE_INITED; 612 iteinit(dev); 613 } 614 615 int 616 ite_param(tp, t) 617 struct tty *tp; 618 struct termios *t; 619 { 620 tp->t_ispeed = t->c_ispeed; 621 tp->t_ospeed = t->c_ospeed; 622 tp->t_cflag = t->c_cflag; 623 return (0); 624 } 625 626 void 627 ite_reset(ip) 628 struct ite_softc *ip; 629 { 630 int i; 631 632 ip->curx = 0; 633 ip->cury = 0; 634 ip->attribute = ATTR_NOR; 635 ip->save_curx = 0; 636 ip->save_cury = 0; 637 ip->save_attribute = ATTR_NOR; 638 ip->ap = ip->argbuf; 639 ip->emul_level = 0; 640 ip->eightbit_C1 = 0; 641 ip->top_margin = 0; 642 ip->bottom_margin = ip->rows - 1; 643 ip->inside_margins = 0; 644 ip->linefeed_newline = 0; 645 ip->auto_wrap = ite_default_wrap; 646 ip->cursor_appmode = 0; 647 ip->keypad_appmode = 0; 648 ip->imode = 0; 649 ip->key_repeat = 1; 650 bzero(ip->tabs, ip->cols); 651 for (i = 0; i < ip->cols; i++) 652 ip->tabs[i] = ((i & 7) == 0); 653 } 654 655 /* 656 * has to be global becuase of the shared filters. 657 */ 658 static u_char key_mod; 659 static u_char last_dead; 660 661 /* Used in console at startup only */ 662 int 663 ite_cnfilter(c, caller) 664 u_char c; 665 enum caller caller; 666 { 667 struct key key; 668 u_char code, up, mask; 669 int s, i; 670 671 up = c & 0x80 ? 1 : 0; 672 c &= 0x7f; 673 code = 0; 674 675 s = spltty(); 676 677 i = (int)c - KBD_LEFT_SHIFT; 678 if (i >= 0 && i <= (KBD_RIGHT_META - KBD_LEFT_SHIFT)) { 679 mask = 1 << i; 680 if (up) 681 key_mod &= ~mask; 682 else 683 key_mod |= mask; 684 splx(s); 685 return -1; 686 } 687 688 if (up) { 689 splx(s); 690 return -1; 691 } 692 693 /* translate modifiers */ 694 if (key_mod & KBD_MOD_SHIFT) { 695 if (key_mod & KBD_MOD_ALT) 696 key = kbdmap.alt_shift_keys[c]; 697 else 698 key = kbdmap.shift_keys[c]; 699 } else if (key_mod & KBD_MOD_ALT) 700 key = kbdmap.alt_keys[c]; 701 else { 702 key = kbdmap.keys[c]; 703 /* if CAPS and key is CAPable (no pun intended) */ 704 if ((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) 705 key = kbdmap.shift_keys[c]; 706 } 707 code = key.code; 708 709 /* if string return */ 710 if (key.mode & (KBD_MODE_STRING | KBD_MODE_KPAD)) { 711 splx(s); 712 return -1; 713 } 714 /* handle dead keys */ 715 if (key.mode & KBD_MODE_DEAD) { 716 /* if entered twice, send accent itself */ 717 if (last_dead == key.mode & KBD_MODE_ACCMASK) 718 last_dead = 0; 719 else { 720 last_dead = key.mode & KBD_MODE_ACCMASK; 721 splx(s); 722 return -1; 723 } 724 } 725 if (last_dead) { 726 /* can't apply dead flag to string-keys */ 727 if (code >= '@' && code < 0x7f) 728 code = 729 acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; 730 last_dead = 0; 731 } 732 if (key_mod & KBD_MOD_CTRL) 733 code &= 0x1f; 734 if (key_mod & KBD_MOD_META) 735 code |= 0x80; 736 737 /* do console mapping. */ 738 code = code == '\r' ? '\n' : code; 739 740 splx(s); 741 return (code); 742 } 743 744 /* And now the old stuff. */ 745 746 /* these are used to implement repeating keys.. */ 747 static u_char last_char; 748 static u_char tout_pending; 749 750 /*ARGSUSED*/ 751 static void 752 repeat_handler(arg) 753 void *arg; 754 { 755 tout_pending = 0; 756 if (last_char) 757 add_sicallback(ite_filter, last_char, ITEFILT_REPEATER); 758 } 759 760 void 761 ite_filter(c, caller) 762 u_char c; 763 enum caller caller; 764 { 765 struct tty *kbd_tty; 766 u_char code, *str, up, mask; 767 struct key key; 768 int s, i; 769 770 if (kbd_ite == NULL) 771 return; 772 773 kbd_tty = kbd_ite->tp; 774 775 /* have to make sure we're at spltty in here */ 776 s = spltty(); 777 778 /* 779 * keyboard interrupts come at priority 2, while softint 780 * generated keyboard-repeat interrupts come at level 1. So, 781 * to not allow a key-up event to get thru before a repeat for 782 * the key-down, we remove any outstanding callout requests.. 783 */ 784 rem_sicallback(ite_filter); 785 786 up = c & 0x80 ? 1 : 0; 787 c &= 0x7f; 788 code = 0; 789 790 i = (int)c - KBD_LEFT_SHIFT; 791 if (i >= 0 && i <= (KBD_RIGHT_META - KBD_LEFT_SHIFT)) { 792 mask = 1 << i; 793 if (up) 794 key_mod &= ~mask; 795 else 796 key_mod |= mask; 797 splx(s); 798 return; 799 } 800 /* stop repeating on up event */ 801 if (up) { 802 if (tout_pending) { 803 untimeout(repeat_handler, 0); 804 tout_pending = 0; 805 last_char = 0; 806 } 807 splx(s); 808 return; 809 } else if (tout_pending && last_char != c) { 810 /* different character, stop also */ 811 untimeout(repeat_handler, 0); 812 tout_pending = 0; 813 last_char = 0; 814 } 815 /* Safety button, switch back to ascii keymap. */ 816 if (key_mod == (KBD_MOD_LALT | KBD_MOD_LMETA) && c == 0x50) { 817 bcopy(&ascii_kbdmap, &kbdmap, sizeof(struct kbdmap)); 818 819 splx(s); 820 return; 821 #ifdef DDB 822 } else if (key_mod == (KBD_MOD_LALT | KBD_MOD_LMETA) && c == 0x59) { 823 extern int Debugger(); 824 Debugger(); 825 splx(s); 826 return; 827 #endif 828 } 829 /* translate modifiers */ 830 if (key_mod & KBD_MOD_SHIFT) { 831 if (key_mod & KBD_MOD_ALT) 832 key = kbdmap.alt_shift_keys[c]; 833 else 834 key = kbdmap.shift_keys[c]; 835 } else if (key_mod & KBD_MOD_ALT) 836 key = kbdmap.alt_keys[c]; 837 else { 838 key = kbdmap.keys[c]; 839 /* if CAPS and key is CAPable (no pun intended) */ 840 if ((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) 841 key = kbdmap.shift_keys[c]; 842 } 843 code = key.code; 844 845 /* 846 * arrange to repeat the keystroke. By doing this at the level 847 * of scan-codes, we can have function keys, and keys that 848 * send strings, repeat too. This also entitles an additional 849 * overhead, since we have to do the conversion each time, but 850 * I guess that's ok. 851 */ 852 if (!tout_pending && caller == ITEFILT_TTY && kbd_ite->key_repeat) { 853 tout_pending = 1; 854 last_char = c; 855 timeout(repeat_handler, 0, start_repeat_timeo * hz / 100); 856 } else if (!tout_pending && caller == ITEFILT_REPEATER && 857 kbd_ite->key_repeat) { 858 tout_pending = 1; 859 last_char = c; 860 timeout(repeat_handler, 0, next_repeat_timeo * hz / 100); 861 } 862 /* handle dead keys */ 863 if (key.mode & KBD_MODE_DEAD) { 864 /* if entered twice, send accent itself */ 865 if (last_dead == key.mode & KBD_MODE_ACCMASK) 866 last_dead = 0; 867 else { 868 last_dead = key.mode & KBD_MODE_ACCMASK; 869 splx(s); 870 return; 871 } 872 } 873 if (last_dead) { 874 /* can't apply dead flag to string-keys */ 875 if (!(key.mode & KBD_MODE_STRING) && code >= '@' && 876 code < 0x7f) 877 code = acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; 878 last_dead = 0; 879 } 880 /* if not string, apply META and CTRL modifiers */ 881 if (!(key.mode & KBD_MODE_STRING) 882 && (!(key.mode & KBD_MODE_KPAD) || 883 (kbd_ite && !kbd_ite->keypad_appmode))) { 884 if (key_mod & KBD_MOD_CTRL) 885 code &= 0x1f; 886 if (key_mod & KBD_MOD_META) 887 code |= 0x80; 888 } else if ((key.mode & KBD_MODE_KPAD) && 889 (kbd_ite && kbd_ite->keypad_appmode)) { 890 static char *in = "0123456789-+.\r()/*"; 891 static char *out = "pqrstuvwxymlnMPQRS"; 892 char *cp = index (in, code); 893 894 /* 895 * keypad-appmode sends SS3 followed by the above 896 * translated character 897 */ 898 (*linesw[kbd_tty->t_line].l_rint) (27, kbd_tty); 899 (*linesw[kbd_tty->t_line].l_rint) ('O', kbd_tty); 900 (*linesw[kbd_tty->t_line].l_rint) (out[cp - in], kbd_tty); 901 splx(s); 902 return; 903 } else { 904 /* *NO* I don't like this.... */ 905 static u_char app_cursor[] = 906 { 907 3, 27, 'O', 'A', 908 3, 27, 'O', 'B', 909 3, 27, 'O', 'C', 910 3, 27, 'O', 'D'}; 911 912 str = kbdmap.strings + code; 913 /* 914 * if this is a cursor key, AND it has the default 915 * keymap setting, AND we're in app-cursor mode, switch 916 * to the above table. This is *nasty* ! 917 */ 918 if (c >= 0x4c && c <= 0x4f && kbd_ite->cursor_appmode 919 && !bcmp(str, "\x03\x1b[", 3) && 920 index("ABCD", str[3])) 921 str = app_cursor + 4 * (str[3] - 'A'); 922 923 /* 924 * using a length-byte instead of 0-termination allows 925 * to embed \0 into strings, although this is not used 926 * in the default keymap 927 */ 928 for (i = *str++; i; i--) 929 (*linesw[kbd_tty->t_line].l_rint) (*str++, kbd_tty); 930 splx(s); 931 return; 932 } 933 (*linesw[kbd_tty->t_line].l_rint) (code, kbd_tty); 934 935 splx(s); 936 return; 937 } 938 939 /* helper functions, makes the code below more readable */ 940 static void inline 941 ite_sendstr(str) 942 char *str; 943 { 944 struct tty *kbd_tty; 945 946 kbd_tty = kbd_ite->tp; 947 KDASSERT(kbd_tty); 948 while (*str) 949 (*linesw[kbd_tty->t_line].l_rint) (*str++, kbd_tty); 950 } 951 952 static void 953 alignment_display(ip) 954 struct ite_softc *ip; 955 { 956 int i, j; 957 958 for (j = 0; j < ip->rows; j++) 959 for (i = 0; i < ip->cols; i++) 960 SUBR_PUTC(ip, 'E', j, i, ATTR_NOR); 961 attrclr(ip, 0, 0, ip->rows, ip->cols); 962 SUBR_CURSOR(ip, DRAW_CURSOR); 963 } 964 965 static void inline 966 snap_cury(ip) 967 struct ite_softc *ip; 968 { 969 if (ip->inside_margins) 970 { 971 if (ip->cury < ip->top_margin) 972 ip->cury = ip->top_margin; 973 if (ip->cury > ip->bottom_margin) 974 ip->cury = ip->bottom_margin; 975 } 976 } 977 978 static void inline 979 ite_dnchar(ip, n) 980 struct ite_softc *ip; 981 int n; 982 { 983 n = min(n, ip->cols - ip->curx); 984 if (n < ip->cols - ip->curx) 985 { 986 SUBR_SCROLL(ip, ip->cury, ip->curx + n, n, SCROLL_LEFT); 987 attrmov(ip, ip->cury, ip->curx + n, ip->cury, ip->curx, 988 1, ip->cols - ip->curx - n); 989 attrclr(ip, ip->cury, ip->cols - n, 1, n); 990 } 991 while (n-- > 0) 992 SUBR_PUTC(ip, ' ', ip->cury, ip->cols - n - 1, ATTR_NOR); 993 SUBR_CURSOR(ip, DRAW_CURSOR); 994 } 995 996 static void inline 997 ite_inchar(ip, n) 998 struct ite_softc *ip; 999 int n; 1000 { 1001 n = min(n, ip->cols - ip->curx); 1002 if (n < ip->cols - ip->curx) 1003 { 1004 SUBR_SCROLL(ip, ip->cury, ip->curx, n, SCROLL_RIGHT); 1005 attrmov(ip, ip->cury, ip->curx, ip->cury, ip->curx + n, 1006 1, ip->cols - ip->curx - n); 1007 attrclr(ip, ip->cury, ip->curx, 1, n); 1008 } 1009 while (n--) 1010 SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); 1011 SUBR_CURSOR(ip, DRAW_CURSOR); 1012 } 1013 1014 static void inline 1015 ite_clrtoeol(ip) 1016 struct ite_softc *ip; 1017 { 1018 int y = ip->cury, x = ip->curx; 1019 if (ip->cols - x > 0) 1020 { 1021 SUBR_CLEAR(ip, y, x, 1, ip->cols - x); 1022 attrclr(ip, y, x, 1, ip->cols - x); 1023 SUBR_CURSOR(ip, DRAW_CURSOR); 1024 } 1025 } 1026 1027 static void inline 1028 ite_clrtobol(ip) 1029 struct ite_softc *ip; 1030 { 1031 int y = ip->cury, x = min(ip->curx + 1, ip->cols); 1032 SUBR_CLEAR(ip, y, 0, 1, x); 1033 attrclr(ip, y, 0, 1, x); 1034 SUBR_CURSOR(ip, DRAW_CURSOR); 1035 } 1036 1037 static void inline 1038 ite_clrline(ip) 1039 struct ite_softc *ip; 1040 { 1041 int y = ip->cury; 1042 SUBR_CLEAR(ip, y, 0, 1, ip->cols); 1043 attrclr(ip, y, 0, 1, ip->cols); 1044 SUBR_CURSOR(ip, DRAW_CURSOR); 1045 } 1046 1047 1048 1049 static void inline 1050 ite_clrtoeos(ip) 1051 struct ite_softc *ip; 1052 { 1053 ite_clrtoeol(ip); 1054 if (ip->cury < ip->rows - 1) 1055 { 1056 SUBR_CLEAR(ip, ip->cury + 1, 0, ip->rows - 1 - ip->cury, ip->cols); 1057 attrclr(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols); 1058 SUBR_CURSOR(ip, DRAW_CURSOR); 1059 } 1060 } 1061 1062 static void inline 1063 ite_clrtobos(ip) 1064 struct ite_softc *ip; 1065 { 1066 ite_clrtobol(ip); 1067 if (ip->cury > 0) 1068 { 1069 SUBR_CLEAR(ip, 0, 0, ip->cury, ip->cols); 1070 attrclr(ip, 0, 0, ip->cury, ip->cols); 1071 SUBR_CURSOR(ip, DRAW_CURSOR); 1072 } 1073 } 1074 1075 static void inline 1076 ite_clrscreen(ip) 1077 struct ite_softc *ip; 1078 { 1079 SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols); 1080 attrclr(ip, 0, 0, ip->rows, ip->cols); 1081 SUBR_CURSOR(ip, DRAW_CURSOR); 1082 } 1083 1084 1085 1086 static void inline 1087 ite_dnline(ip, n) 1088 struct ite_softc *ip; 1089 int n; 1090 { 1091 /* interesting.. if the cursor is outside the scrolling 1092 region, this command is simply ignored.. */ 1093 if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) 1094 return; 1095 1096 n = min(n, ip->bottom_margin + 1 - ip->cury); 1097 if (n <= ip->bottom_margin - ip->cury) 1098 { 1099 SUBR_SCROLL(ip, ip->cury + n, 0, n, SCROLL_UP); 1100 attrmov(ip, ip->cury + n, 0, ip->cury, 0, 1101 ip->bottom_margin + 1 - ip->cury - n, ip->cols); 1102 } 1103 SUBR_CLEAR(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); 1104 attrclr(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); 1105 SUBR_CURSOR(ip, DRAW_CURSOR); 1106 } 1107 1108 static void inline 1109 ite_inline(ip, n) 1110 struct ite_softc *ip; 1111 int n; 1112 { 1113 /* interesting.. if the cursor is outside the scrolling 1114 region, this command is simply ignored.. */ 1115 if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) 1116 return; 1117 1118 n = min(n, ip->bottom_margin + 1 - ip->cury); 1119 if (n <= ip->bottom_margin - ip->cury) 1120 { 1121 SUBR_SCROLL(ip, ip->cury, 0, n, SCROLL_DOWN); 1122 attrmov(ip, ip->cury, 0, ip->cury + n, 0, 1123 ip->bottom_margin + 1 - ip->cury - n, ip->cols); 1124 } 1125 SUBR_CLEAR(ip, ip->cury, 0, n, ip->cols); 1126 attrclr(ip, ip->cury, 0, n, ip->cols); 1127 SUBR_CURSOR(ip, DRAW_CURSOR); 1128 } 1129 1130 static void inline 1131 ite_lf (ip) 1132 struct ite_softc *ip; 1133 { 1134 ++ip->cury; 1135 if ((ip->cury == ip->bottom_margin+1) || (ip->cury == ip->rows)) 1136 { 1137 ip->cury--; 1138 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); 1139 ite_clrline(ip); 1140 } 1141 SUBR_CURSOR(ip, MOVE_CURSOR); 1142 clr_attr(ip, ATTR_INV); 1143 } 1144 1145 static void inline 1146 ite_crlf (ip) 1147 struct ite_softc *ip; 1148 { 1149 ip->curx = 0; 1150 ite_lf (ip); 1151 } 1152 1153 static void inline 1154 ite_cr (ip) 1155 struct ite_softc *ip; 1156 { 1157 if (ip->curx) 1158 { 1159 ip->curx = 0; 1160 SUBR_CURSOR(ip, MOVE_CURSOR); 1161 } 1162 } 1163 1164 static void inline 1165 ite_rlf (ip) 1166 struct ite_softc *ip; 1167 { 1168 ip->cury--; 1169 if ((ip->cury < 0) || (ip->cury == ip->top_margin - 1)) 1170 { 1171 ip->cury++; 1172 SUBR_SCROLL(ip, ip->top_margin, 0, 1, SCROLL_DOWN); 1173 ite_clrline(ip); 1174 } 1175 SUBR_CURSOR(ip, MOVE_CURSOR); 1176 clr_attr(ip, ATTR_INV); 1177 } 1178 1179 static int inline 1180 atoi (cp) 1181 const char *cp; 1182 { 1183 int n; 1184 1185 for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++) 1186 n = n * 10 + *cp - '0'; 1187 1188 return n; 1189 } 1190 1191 static char * 1192 index (cp, ch) 1193 const char *cp; 1194 char ch; 1195 { 1196 while (*cp && *cp != ch) cp++; 1197 return *cp ? (char *) cp : 0; 1198 } 1199 1200 1201 1202 static int inline 1203 ite_argnum (ip) 1204 struct ite_softc *ip; 1205 { 1206 char ch; 1207 int n; 1208 1209 /* convert argument string into number */ 1210 if (ip->ap == ip->argbuf) 1211 return 1; 1212 ch = *ip->ap; 1213 *ip->ap = 0; 1214 n = atoi (ip->argbuf); 1215 *ip->ap = ch; 1216 1217 return n; 1218 } 1219 1220 static int inline 1221 ite_zargnum (ip) 1222 struct ite_softc *ip; 1223 { 1224 char ch, *cp; 1225 int n; 1226 1227 /* convert argument string into number */ 1228 if (ip->ap == ip->argbuf) 1229 return 0; 1230 ch = *ip->ap; 1231 *ip->ap = 0; 1232 n = atoi (ip->argbuf); 1233 *ip->ap = ch; 1234 1235 return n; /* don't "n ? n : 1" here, <CSI>0m != <CSI>1m ! */ 1236 } 1237 1238 static int inline 1239 strncmp (a, b, l) 1240 const char *a, *b; 1241 int l; 1242 { 1243 for (;l--; a++, b++) 1244 if (*a != *b) 1245 return *a - *b; 1246 return 0; 1247 } 1248 1249 void 1250 ite_putstr(s, len, dev) 1251 const char *s; 1252 int len; 1253 dev_t dev; 1254 { 1255 struct ite_softc *ip; 1256 int i; 1257 1258 ip = getitesp(dev); 1259 1260 /* XXX avoid problems */ 1261 if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) 1262 return; 1263 1264 SUBR_CURSOR(ip, START_CURSOROPT); 1265 for (i = 0; i < len; i++) 1266 if (s[i]) 1267 iteputchar(s[i], ip); 1268 SUBR_CURSOR(ip, END_CURSOROPT); 1269 } 1270 1271 1272 void 1273 iteputchar(c, ip) 1274 register int c; 1275 struct ite_softc *ip; 1276 { 1277 struct tty *kbd_tty; 1278 int n, x, y; 1279 char *cp; 1280 1281 if (kbd_ite == NULL) 1282 kbd_tty = NULL; 1283 else 1284 kbd_tty = kbd_ite->tp; 1285 1286 if (ip->escape) { 1287 doesc: 1288 switch (ip->escape) { 1289 case ESC: 1290 switch (c) { 1291 /* 1292 * first 7bit equivalents for the 1293 * 8bit control characters 1294 */ 1295 case 'D': 1296 c = IND; 1297 ip->escape = 0; 1298 break; 1299 /* 1300 * and fall into the next 1301 * switch below (same for all `break') 1302 */ 1303 case 'E': 1304 c = NEL; 1305 ip->escape = 0; 1306 break; 1307 case 'H': 1308 c = HTS; 1309 ip->escape = 0; 1310 break; 1311 case 'M': 1312 c = RI; 1313 ip->escape = 0; 1314 break; 1315 case 'N': 1316 c = SS2; 1317 ip->escape = 0; 1318 break; 1319 case 'O': 1320 c = SS3; 1321 ip->escape = 0; 1322 break; 1323 case 'P': 1324 c = DCS; 1325 ip->escape = 0; 1326 break; 1327 case '[': 1328 c = CSI; 1329 ip->escape = 0; 1330 break; 1331 case '\\': 1332 c = ST; 1333 ip->escape = 0; 1334 break; 1335 case ']': 1336 c = OSC; 1337 ip->escape = 0; 1338 break; 1339 case '^': 1340 c = PM; 1341 ip->escape = 0; 1342 break; 1343 case '_': 1344 c = APC; 1345 ip->escape = 0; 1346 break; 1347 /* introduces 7/8bit control */ 1348 case ' ': 1349 /* can be followed by either F or G */ 1350 ip->escape = ' '; 1351 break; 1352 /* 1353 * a lot of character set selections, not yet 1354 * used... 94-character sets: 1355 */ 1356 case '(': /* G0 */ 1357 case ')': /* G1 */ 1358 ip->escape = c; 1359 return; 1360 case '*': /* G2 */ 1361 case '+': /* G3 */ 1362 case 'B': /* ASCII */ 1363 case 'A': /* ISO latin 1 */ 1364 case '<': /* user preferred suplemental */ 1365 case '0': /* dec special graphics */ 1366 /* 1367 * 96-character sets: 1368 */ 1369 case '-': /* G1 */ 1370 case '.': /* G2 */ 1371 case '/': /* G3 */ 1372 /* 1373 * national character sets: 1374 */ 1375 case '4': /* dutch */ 1376 case '5': 1377 case 'C': /* finnish */ 1378 case 'R': /* french */ 1379 case 'Q': /* french canadian */ 1380 case 'K': /* german */ 1381 case 'Y': /* italian */ 1382 case '6': /* norwegian/danish */ 1383 /* 1384 * note: %5 and %6 are not supported (two 1385 * chars..) 1386 */ 1387 ip->escape = 0; 1388 /* just ignore for now */ 1389 return; 1390 /* 1391 * locking shift modes (as you might guess, not 1392 * yet supported..) 1393 */ 1394 case '`': 1395 ip->GR = ip->G1; 1396 ip->escape = 0; 1397 return; 1398 case 'n': 1399 ip->GL = ip->G2; 1400 ip->escape = 0; 1401 return; 1402 case '}': 1403 ip->GR = ip->G2; 1404 ip->escape = 0; 1405 return; 1406 case 'o': 1407 ip->GL = ip->G3; 1408 ip->escape = 0; 1409 return; 1410 case '|': 1411 ip->GR = ip->G3; 1412 ip->escape = 0; 1413 return; 1414 case '#': 1415 /* font width/height control */ 1416 ip->escape = '#'; 1417 return; 1418 case 'c': 1419 /* hard terminal reset .. */ 1420 ite_reset(ip); 1421 SUBR_CURSOR(ip, MOVE_CURSOR); 1422 ip->escape = 0; 1423 return; 1424 case '7': 1425 ip->save_curx = ip->curx; 1426 ip->save_cury = ip->cury; 1427 ip->save_attribute = ip->attribute; 1428 ip->escape = 0; 1429 return; 1430 case '8': 1431 ip->curx = ip->save_curx; 1432 ip->cury = ip->save_cury; 1433 ip->attribute = ip->save_attribute; 1434 SUBR_CURSOR(ip, MOVE_CURSOR); 1435 ip->escape = 0; 1436 return; 1437 case '=': 1438 ip->keypad_appmode = 1; 1439 ip->escape = 0; 1440 return; 1441 case '>': 1442 ip->keypad_appmode = 0; 1443 ip->escape = 0; 1444 return; 1445 case 'Z': /* request ID */ 1446 /* XXX not clean */ 1447 if (ip->emul_level == EMUL_VT100) 1448 ite_sendstr("\033[?61;0c"); 1449 else 1450 ite_sendstr("\033[?63;0c"); 1451 ip->escape = 0; 1452 return; 1453 default: 1454 /* 1455 * default catch all for not recognized ESC 1456 * sequences 1457 */ 1458 ip->escape = 0; 1459 return; 1460 } 1461 break; 1462 case '(': 1463 case ')': 1464 ip->escape = 0; 1465 return; 1466 case ' ': 1467 switch (c) { 1468 case 'F': 1469 ip->eightbit_C1 = 0; 1470 ip->escape = 0; 1471 return; 1472 case 'G': 1473 ip->eightbit_C1 = 1; 1474 ip->escape = 0; 1475 return; 1476 default: 1477 /* not supported */ 1478 ip->escape = 0; 1479 return; 1480 } 1481 break; 1482 case '#': 1483 switch (c) { 1484 case '5': 1485 /* single height, single width */ 1486 ip->escape = 0; 1487 return; 1488 case '6': 1489 /* double width, single height */ 1490 ip->escape = 0; 1491 return; 1492 case '3': 1493 /* top half */ 1494 ip->escape = 0; 1495 return; 1496 case '4': 1497 /* bottom half */ 1498 ip->escape = 0; 1499 return; 1500 case '8': 1501 /* screen alignment pattern... */ 1502 alignment_display(ip); 1503 ip->escape = 0; 1504 return; 1505 default: 1506 ip->escape = 0; 1507 return; 1508 } 1509 break; 1510 case CSI: 1511 /* the biggie... */ 1512 switch (c) { 1513 case '0': 1514 case '1': 1515 case '2': 1516 case '3': 1517 case '4': 1518 case '5': 1519 case '6': 1520 case '7': 1521 case '8': 1522 case '9': 1523 case ';': 1524 case '\"': 1525 case '$': 1526 case '>': 1527 if (ip->ap < ip->argbuf + MAX_ARGSIZE) 1528 *ip->ap++ = c; 1529 return; 1530 case BS: 1531 /* 1532 * you wouldn't believe such perversion is 1533 * possible? it is.. BS is allowed in between 1534 * cursor sequences (at least), according to 1535 * vttest.. 1536 */ 1537 if (--ip->curx < 0) 1538 ip->curx = 0; 1539 else 1540 SUBR_CURSOR(ip, MOVE_CURSOR); 1541 break; 1542 case 'p': 1543 *ip->ap = 0; 1544 if (!strncmp(ip->argbuf, "61\"", 3)) 1545 ip->emul_level = EMUL_VT100; 1546 else if (!strncmp(ip->argbuf, "63;1\"", 5) 1547 || !strncmp(ip->argbuf, "62;1\"", 5)) 1548 ip->emul_level = EMUL_VT300_7; 1549 else 1550 ip->emul_level = EMUL_VT300_8; 1551 ip->escape = 0; 1552 return; 1553 case '?': 1554 *ip->ap = 0; 1555 ip->escape = '?'; 1556 ip->ap = ip->argbuf; 1557 return; 1558 case 'c': 1559 *ip->ap = 0; 1560 if (ip->argbuf[0] == '>') { 1561 ite_sendstr("\033[>24;0;0;0c"); 1562 } else 1563 switch (ite_zargnum(ip)) { 1564 case 0: 1565 /* 1566 * primary DA request, send 1567 * primary DA response 1568 */ 1569 if (ip->emul_level 1570 == EMUL_VT100) 1571 ite_sendstr( 1572 "\033[?1;1c"); 1573 else 1574 ite_sendstr( 1575 "\033[?63;1c"); 1576 break; 1577 } 1578 ip->escape = 0; 1579 return; 1580 case 'n': 1581 switch (ite_zargnum(ip)) { 1582 case 5: 1583 /* no malfunction */ 1584 ite_sendstr("\033[0n"); 1585 break; 1586 case 6: 1587 /* cursor position report */ 1588 sprintf(ip->argbuf, "\033[%d;%dR", 1589 ip->cury + 1, ip->curx + 1); 1590 ite_sendstr(ip->argbuf); 1591 break; 1592 } 1593 ip->escape = 0; 1594 return; 1595 case 'x': 1596 switch (ite_zargnum(ip)) { 1597 case 0: 1598 /* Fake some terminal parameters. */ 1599 ite_sendstr("\033[2;1;1;112;112;1;0x"); 1600 break; 1601 case 1: 1602 ite_sendstr("\033[3;1;1;112;112;1;0x"); 1603 break; 1604 } 1605 ip->escape = 0; 1606 return; 1607 case 'g': 1608 switch (ite_zargnum(ip)) { 1609 case 0: 1610 if (ip->curx < ip->cols) 1611 ip->tabs[ip->curx] = 0; 1612 break; 1613 case 3: 1614 for (n = 0; n < ip->cols; n++) 1615 ip->tabs[n] = 0; 1616 break; 1617 } 1618 ip->escape = 0; 1619 return; 1620 case 'h': 1621 case 'l': 1622 n = ite_zargnum(ip); 1623 switch (n) { 1624 case 4: 1625 /* insert/replace mode */ 1626 ip->imode = (c == 'h'); 1627 break; 1628 case 20: 1629 ip->linefeed_newline = (c == 'h'); 1630 break; 1631 } 1632 ip->escape = 0; 1633 return; 1634 case 'M': 1635 ite_dnline(ip, ite_argnum(ip)); 1636 ip->escape = 0; 1637 return; 1638 case 'L': 1639 ite_inline(ip, ite_argnum(ip)); 1640 ip->escape = 0; 1641 return; 1642 case 'P': 1643 ite_dnchar(ip, ite_argnum(ip)); 1644 ip->escape = 0; 1645 return; 1646 case '@': 1647 ite_inchar(ip, ite_argnum(ip)); 1648 ip->escape = 0; 1649 return; 1650 case 'G': 1651 /* 1652 * this one was *not* in my vt320 manual but in 1653 * a vt320 termcap entry.. who is right? It's 1654 * supposed to set the horizontal cursor 1655 * position. 1656 */ 1657 *ip->ap = 0; 1658 x = atoi(ip->argbuf); 1659 if (x) 1660 x--; 1661 ip->curx = min(x, ip->cols - 1); 1662 ip->escape = 0; 1663 SUBR_CURSOR(ip, MOVE_CURSOR); 1664 clr_attr(ip, ATTR_INV); 1665 return; 1666 case 'd': 1667 /* 1668 * same thing here, this one's for setting the 1669 * absolute vertical cursor position. Not 1670 * documented... 1671 */ 1672 *ip->ap = 0; 1673 y = atoi(ip->argbuf); 1674 if (y) 1675 y--; 1676 if (ip->inside_margins) 1677 y += ip->top_margin; 1678 ip->cury = min(y, ip->rows - 1); 1679 ip->escape = 0; 1680 snap_cury(ip); 1681 SUBR_CURSOR(ip, MOVE_CURSOR); 1682 clr_attr(ip, ATTR_INV); 1683 return; 1684 case 'H': 1685 case 'f': 1686 *ip->ap = 0; 1687 y = atoi(ip->argbuf); 1688 x = 0; 1689 cp = index(ip->argbuf, ';'); 1690 if (cp) 1691 x = atoi(cp + 1); 1692 if (x) 1693 x--; 1694 if (y) 1695 y--; 1696 if (ip->inside_margins) 1697 y += ip->top_margin; 1698 ip->cury = min(y, ip->rows - 1); 1699 ip->curx = min(x, ip->cols - 1); 1700 ip->escape = 0; 1701 snap_cury(ip); 1702 SUBR_CURSOR(ip, MOVE_CURSOR); 1703 clr_attr(ip, ATTR_INV); 1704 return; 1705 case 'A': 1706 n = ite_argnum(ip); 1707 n = ip->cury - (n ? n : 1); 1708 if (n < 0) 1709 n = 0; 1710 if (ip->inside_margins) 1711 n = max(ip->top_margin, n); 1712 else if (n == ip->top_margin - 1) 1713 /* 1714 * allow scrolling outside region, but 1715 * don't scroll out of active region 1716 * without explicit CUP 1717 */ 1718 n = ip->top_margin; 1719 ip->cury = n; 1720 ip->escape = 0; 1721 SUBR_CURSOR(ip, MOVE_CURSOR); 1722 clr_attr(ip, ATTR_INV); 1723 return; 1724 case 'B': 1725 n = ite_argnum(ip); 1726 n = ip->cury + (n ? n : 1); 1727 n = min(ip->rows - 1, n); 1728 if (ip->inside_margins) 1729 n = min(ip->bottom_margin, n); 1730 else if (n == ip->bottom_margin + 1) 1731 /* 1732 * allow scrolling outside region, but 1733 * don't scroll out of active region 1734 * without explicit CUP 1735 */ 1736 n = ip->bottom_margin; 1737 ip->cury = n; 1738 ip->escape = 0; 1739 SUBR_CURSOR(ip, MOVE_CURSOR); 1740 clr_attr(ip, ATTR_INV); 1741 return; 1742 case 'C': 1743 n = ite_argnum(ip); 1744 n = n ? n : 1; 1745 ip->curx = min(ip->curx + n, ip->cols - 1); 1746 ip->escape = 0; 1747 SUBR_CURSOR(ip, MOVE_CURSOR); 1748 clr_attr(ip, ATTR_INV); 1749 return; 1750 case 'D': 1751 n = ite_argnum(ip); 1752 n = n ? n : 1; 1753 n = ip->curx - n; 1754 ip->curx = n >= 0 ? n : 0; 1755 ip->escape = 0; 1756 SUBR_CURSOR(ip, MOVE_CURSOR); 1757 clr_attr(ip, ATTR_INV); 1758 return; 1759 case 'J': 1760 *ip->ap = 0; 1761 n = ite_zargnum(ip); 1762 if (n == 0) 1763 ite_clrtoeos(ip); 1764 else if (n == 1) 1765 ite_clrtobos(ip); 1766 else if (n == 2) 1767 ite_clrscreen(ip); 1768 ip->escape = 0; 1769 return; 1770 case 'K': 1771 n = ite_zargnum(ip); 1772 if (n == 0) 1773 ite_clrtoeol(ip); 1774 else if (n == 1) 1775 ite_clrtobol(ip); 1776 else if (n == 2) 1777 ite_clrline(ip); 1778 ip->escape = 0; 1779 return; 1780 case 'X': 1781 n = ite_argnum(ip) - 1; 1782 n = min(n, ip->cols - 1 - ip->curx); 1783 for (; n >= 0; n--) { 1784 attrclr(ip, ip->cury, ip->curx + n, 1, 1); 1785 SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); 1786 } 1787 ip->escape = 0; 1788 return; 1789 case '}': 1790 case '`': 1791 /* status line control */ 1792 ip->escape = 0; 1793 return; 1794 case 'r': 1795 *ip->ap = 0; 1796 x = atoi(ip->argbuf); 1797 x = x ? x : 1; 1798 y = ip->rows; 1799 cp = index(ip->argbuf, ';'); 1800 if (cp) { 1801 y = atoi(cp + 1); 1802 y = y ? y : ip->rows; 1803 } 1804 if (y - x < 2) { 1805 /* 1806 * if illegal scrolling region, reset 1807 * to defaults 1808 */ 1809 x = 1; 1810 y = ip->rows; 1811 } 1812 x--; 1813 y--; 1814 ip->top_margin = min(x, ip->rows - 1); 1815 ip->bottom_margin = min(y, ip->rows - 1); 1816 if (ip->inside_margins) { 1817 ip->cury = ip->top_margin; 1818 ip->curx = 0; 1819 SUBR_CURSOR(ip, MOVE_CURSOR); 1820 } 1821 ip->escape = 0; 1822 return; 1823 case 'm': 1824 /* big attribute setter/resetter */ 1825 { char *cp; 1826 *ip->ap = 0; 1827 /* kludge to make CSIm work (== CSI0m) */ 1828 if (ip->ap == ip->argbuf) 1829 ip->ap++; 1830 for (cp = ip->argbuf; cp < ip->ap;) { 1831 switch (*cp) { 1832 case 0: 1833 case '0': 1834 clr_attr(ip, ATTR_ALL); 1835 cp++; 1836 break; 1837 1838 case '1': 1839 set_attr(ip, ATTR_BOLD); 1840 cp++; 1841 break; 1842 1843 case '2': 1844 switch (cp[1]) { 1845 case '2': 1846 clr_attr(ip, ATTR_BOLD); 1847 cp += 2; 1848 break; 1849 1850 case '4': 1851 clr_attr(ip, ATTR_UL); 1852 cp += 2; 1853 break; 1854 1855 case '5': 1856 clr_attr(ip, ATTR_BLINK); 1857 cp += 2; 1858 break; 1859 1860 case '7': 1861 clr_attr(ip, ATTR_INV); 1862 cp += 2; 1863 break; 1864 1865 default: 1866 cp++; 1867 break; 1868 } 1869 break; 1870 1871 case '4': 1872 set_attr(ip, ATTR_UL); 1873 cp++; 1874 break; 1875 1876 case '5': 1877 set_attr(ip, ATTR_BLINK); 1878 cp++; 1879 break; 1880 1881 case '7': 1882 set_attr(ip, ATTR_INV); 1883 cp++; 1884 break; 1885 1886 default: 1887 cp++; 1888 break; 1889 } 1890 } 1891 ip->escape = 0; 1892 return; } 1893 case 'u': 1894 /* DECRQTSR */ 1895 ite_sendstr("\033P\033\\"); 1896 ip->escape = 0; 1897 return; 1898 default: 1899 ip->escape = 0; 1900 return; 1901 } 1902 break; 1903 case '?': /* CSI ? */ 1904 switch (c) { 1905 case '0': 1906 case '1': 1907 case '2': 1908 case '3': 1909 case '4': 1910 case '5': 1911 case '6': 1912 case '7': 1913 case '8': 1914 case '9': 1915 case ';': 1916 case '\"': 1917 case '$': 1918 /* 1919 * Don't fill the last character; 1920 * it's needed. 1921 * XXX yeah, where ?? 1922 */ 1923 if (ip->ap < ip->argbuf + MAX_ARGSIZE - 1) 1924 *ip->ap++ = c; 1925 return; 1926 case 'n': 1927 *ip->ap = 0; 1928 if (ip->ap == &ip->argbuf[2]) { 1929 if (!strncmp(ip->argbuf, "15", 2)) 1930 /* printer status: no printer */ 1931 ite_sendstr("\033[13n"); 1932 1933 else if (!strncmp(ip->argbuf, "25", 2)) 1934 /* udk status */ 1935 ite_sendstr("\033[20n"); 1936 1937 else if (!strncmp(ip->argbuf, "26", 2)) 1938 /* keyboard dialect: US */ 1939 ite_sendstr("\033[27;1n"); 1940 } 1941 ip->escape = 0; 1942 return; 1943 case 'h': 1944 case 'l': 1945 n = ite_zargnum(ip); 1946 switch (n) { 1947 case 1: 1948 ip->cursor_appmode = (c == 'h'); 1949 break; 1950 case 3: 1951 /* 132/80 columns (132 == 'h') */ 1952 break; 1953 case 4: /* smooth scroll */ 1954 break; 1955 case 5: 1956 /* 1957 * light background (=='h') /dark 1958 * background(=='l') 1959 */ 1960 break; 1961 case 6: /* origin mode */ 1962 ip->inside_margins = (c == 'h'); 1963 ip->curx = 0; 1964 ip->cury = ip->inside_margins ? 1965 ip->top_margin : 0; 1966 SUBR_CURSOR(ip, MOVE_CURSOR); 1967 break; 1968 case 7: /* auto wraparound */ 1969 ip->auto_wrap = (c == 'h'); 1970 break; 1971 case 8: /* keyboard repeat */ 1972 ip->key_repeat = (c == 'h'); 1973 break; 1974 case 20: /* newline mode */ 1975 ip->linefeed_newline = (c == 'h'); 1976 break; 1977 case 25: /* cursor on/off */ 1978 SUBR_CURSOR(ip, (c == 'h') ? 1979 DRAW_CURSOR : ERASE_CURSOR); 1980 break; 1981 } 1982 ip->escape = 0; 1983 return; 1984 default: 1985 ip->escape = 0; 1986 return; 1987 } 1988 break; 1989 default: 1990 ip->escape = 0; 1991 return; 1992 } 1993 } 1994 switch (c) { 1995 case VT: /* VT is treated like LF */ 1996 case FF: /* so is FF */ 1997 case LF: 1998 /* 1999 * cr->crlf distinction is done here, on output, not on input! 2000 */ 2001 if (ip->linefeed_newline) 2002 ite_crlf(ip); 2003 else 2004 ite_lf(ip); 2005 break; 2006 case CR: 2007 ite_cr(ip); 2008 break; 2009 case BS: 2010 if (--ip->curx < 0) 2011 ip->curx = 0; 2012 else 2013 SUBR_CURSOR(ip, MOVE_CURSOR); 2014 break; 2015 case HT: 2016 for (n = ip->curx + 1; n < ip->cols; n++) { 2017 if (ip->tabs[n]) { 2018 ip->curx = n; 2019 SUBR_CURSOR(ip, MOVE_CURSOR); 2020 break; 2021 } 2022 } 2023 break; 2024 case BEL: 2025 if (kbd_tty && kbd_ite && kbd_ite->tp == kbd_tty) 2026 kbdbell(); 2027 break; 2028 case SO: 2029 ip->GL = ip->G1; 2030 break; 2031 case SI: 2032 ip->GL = ip->G0; 2033 break; 2034 case ENQ: 2035 /* send answer-back message !! */ 2036 break; 2037 case CAN: 2038 ip->escape = 0; /* cancel any escape sequence in progress */ 2039 break; 2040 case SUB: 2041 ip->escape = 0; /* dito, but see below */ 2042 /* should also display a reverse question mark!! */ 2043 break; 2044 case ESC: 2045 ip->escape = ESC; 2046 break; 2047 /* 2048 * now it gets weird.. 8bit control sequences.. 2049 */ 2050 case IND: 2051 /* index: move cursor down, scroll */ 2052 ite_lf(ip); 2053 break; 2054 case NEL: 2055 /* next line. next line, first pos. */ 2056 ite_crlf(ip); 2057 break; 2058 case HTS: 2059 /* set horizontal tab */ 2060 if (ip->curx < ip->cols) 2061 ip->tabs[ip->curx] = 1; 2062 break; 2063 case RI: 2064 /* reverse index */ 2065 ite_rlf(ip); 2066 break; 2067 case SS2: 2068 /* go into G2 for one character */ 2069 /* not yet supported */ 2070 break; 2071 case SS3: 2072 /* go into G3 for one character */ 2073 break; 2074 case DCS: 2075 /* device control string introducer */ 2076 ip->escape = DCS; 2077 ip->ap = ip->argbuf; 2078 break; 2079 case CSI: 2080 /* control sequence introducer */ 2081 ip->escape = CSI; 2082 ip->ap = ip->argbuf; 2083 break; 2084 case ST: 2085 /* string terminator */ 2086 /* ignore, if not used as terminator */ 2087 break; 2088 case OSC: 2089 /* 2090 * introduces OS command. Ignore everything 2091 * upto ST 2092 */ 2093 ip->escape = OSC; 2094 break; 2095 case PM: 2096 /* privacy message, ignore everything upto ST */ 2097 ip->escape = PM; 2098 break; 2099 case APC: 2100 /* 2101 * application program command, ignore * everything upto ST 2102 */ 2103 ip->escape = APC; 2104 break; 2105 default: 2106 if ((c & 0x7f) < ' ' || c == DEL) 2107 break; 2108 if (ip->imode) 2109 ite_inchar(ip, 1); 2110 iteprecheckwrap(ip); 2111 #ifdef DO_WEIRD_ATTRIBUTES 2112 if ((ip->attribute & ATTR_INV) || attrtest(ip, ATTR_INV)) { 2113 attrset(ip, ATTR_INV); 2114 SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_INV); 2115 } else 2116 SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_NOR); 2117 #else 2118 SUBR_PUTC(ip, c, ip->cury, ip->curx, ip->attribute); 2119 #endif 2120 SUBR_CURSOR(ip, DRAW_CURSOR); 2121 itecheckwrap(ip); 2122 break; 2123 } 2124 } 2125 2126 int 2127 iteprecheckwrap(ip) 2128 struct ite_softc *ip; 2129 { 2130 if (ip->auto_wrap && ip->curx == ip->cols) { 2131 ip->curx = 0; 2132 clr_attr(ip, ATTR_INV); 2133 if (++ip->cury >= ip->bottom_margin + 1) { 2134 ip->cury = ip->bottom_margin; 2135 SUBR_CURSOR(ip, MOVE_CURSOR); 2136 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); 2137 ite_clrtoeol(ip); 2138 } else 2139 SUBR_CURSOR(ip, MOVE_CURSOR); 2140 } 2141 } 2142 2143 int 2144 itecheckwrap(ip) 2145 struct ite_softc *ip; 2146 { 2147 #if 0 2148 if (++ip->curx == ip->cols) { 2149 if (ip->auto_wrap) { 2150 ip->curx = 0; 2151 clr_attr(ip, ATTR_INV); 2152 if (++ip->cury >= ip->bottom_margin + 1) { 2153 ip->cury = ip->bottom_margin; 2154 SUBR_CURSOR(ip, MOVE_CURSOR); 2155 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); 2156 ite_clrtoeol(ip); 2157 return; 2158 } 2159 } else 2160 /* stay there if no autowrap.. */ 2161 ip->curx--; 2162 } 2163 #else 2164 if (ip->curx < ip->cols) { 2165 ip->curx++; 2166 SUBR_CURSOR(ip, MOVE_CURSOR); 2167 } 2168 #endif 2169 } 2170