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